forked from cisco/libfnr
/
HOWTO.txt
100 lines (77 loc) · 4.82 KB
/
HOWTO.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
libFNR is a utility to do small block encryption, with a variable sized block
between 1 and 128 bits, and with no ciphertext expansion (that is, the
ciphertext is precisely the same length as the plaintext)
It isn't very efficient (it's not; after all, every encryption or decryption
operation involves 7 calls to AES); it is designed to be secure.
Here are the concepts behind it:
- key -- This is the secret used to specify how to transform. This is the
part that you share between the encryptor and decryptor, and what
needs to be kept secret from anyone listening in. We use the same
key sizes as AES (128, 192, 256 bits; expressed as a byte string).
- tweak -- This is a parameter that modifies how the encryption is done.
This is designed so that the same key can be used to protect
different fields, in such a way so that if someone learns that
plaintext xxx corresponds to ciphertext yyy in context A, they still
have no information what yyy means in context B. The idea is that
you'd use a string the identifies the context as the tweak. As such,
the tweak has the following properties: 1) the encryption process
with the same key and two different tweaks are unrelated; 2) there is
no security problem with making the tweak public (unlike the key),
3) the tweak is cheap to update (a lot cheaper than the key, in this
case)
We support arbitrary bytestrings as tweaks
- plaintext/ciphertext -- These are n-bit binary fields, with n being
between 1 and 128 (and you specify it while expanding the key).
These are represented by strings of unsigned char's, with each
unsigned char holding 8 bits. If n is not a multiple of 8, then we
handle the last partial byte by using the lsbits in the last byte;
the msbits of that unsigned char are assumed not to be a part of the
plaintext/ciphertext
Now, encryption/decryption is deterministic; if we encrypt the same
plaintext twice with the same key and tweak, you will always get the same
ciphertext. This is a side effect of not having any ciphertext expansion,
there are 2N possible plaintexts and 2N possible ciphertexts, and so
(for a fixed key/tweak) there has to be a 1:1 mapping.
Here's how you use it:
Step 1: convert your key (128, 192 or 256 bit -- this is based on AES, and
this key will be directly fed to it) into expanded form:
fnr_expanded_key key = FNR_expand_key( aes_key, aes_key_size,
block_size );
if (!key) error_handling();
The block_size parameter is the of blocks we'll encrypt with this key; it
must be a value between 1 and 128 bits. Why anyone would want to encrypt
a 1 bit block, I have no idea, but still...
You can reuse this key every time you need to encrypt or decrypt with this
key and this block size. If you want to use the same key with a different
block size, that's fine (that won't cause a security problem), but you'll
need to re-expand the key
Step 2: expand your tweak (which is public data that modifies how the
encryption is done; one way of thinking of this is to look at it as another
part of the key, but one which can be made public, and which is cheap to
change):
fnr_expanded_tweak tweak;
FNR_expand_tweak(&tweak, key, arbitrary_bytestring, length_of_bytestring);
The tweak may consist of an arbitrary bytestring.
If you use the same tweak for multiple encryptions/decryptions, you can use
the same expanded tweak.
If you don't have a tweak, you need to expand a 0-length tweak. Perhaps we
could have the encrypt/decrypt routines interpret a NULL tweak as the
0-length; we currently don't bother (as 0-length tweaks may not occur often
enough)
Step 3: encrypt and decrypt your data
FNR_encrypt(key, &tweak, plaintext, ciphertext);
FNR_decrypt(key, &tweak, ciphertext, plaintext);
Encrypting/decrypting in place (plaintext==ciphertext) is allowed; because
the plaintext and the ciphertext are the same size, you may want to do this
Here, plaintext and ciphertext are the number of bits long you specified
when you expanded the key. Now, if you specified a length that's not a
multiple of 8, here's how we handle that case: if you specify such an odd
size N, we take all the N/8 bytes, plus the remaining N%8 lsbits from the
next byte. When we write, we are careful not to disturb any bits outside the
N bit region. For example, if we have a 4 bit ciphertext, we'll update the
lower 4 bits of ciphertext, and leave the remaining upper 4 bits
undisturbed.
Step last: when you're done with the key, you discard it with:
FNR_zeroize_key(key);
FNR_shut();
(there's no need to zeroize the expanded tweak)