Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e042dc3

Browse files
committed
Reformat text
1 parent 94f9962 commit e042dc3

1 file changed

Lines changed: 76 additions & 39 deletions

File tree

draft-RNCryptor-Spec-v4.0.md

Lines changed: 76 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,26 @@
1818

1919
All data is in network order (big-endian).
2020

21-
Note that the version of the RNCryptor ObjC library is not directly related to the version of the RNCryptor file format. For example, v2.2 of the RNCryptor ObjC library writes v3 of the file format. The versioning of an implementation is related to its API, not the file formats it supports.
21+
Note that the version of the RNCryptor ObjC library is not directly related to
22+
the version of the RNCryptor file format. For example, v2.2 of the RNCryptor
23+
ObjC library writes v3 of the file format. The versioning of an implementation
24+
is related to its API, not the file formats it supports.
2225

2326
## Key Generation
2427

25-
RNCryptor uses either a 256-bit random key or a password. It extracts a 512-bit pseudorandom key (PRK) from this using HKDF-Extract or PBKDF2. It then uses HKDF-Expand to expand this key material into the IV, a validation token, the encryption key, and the HMAC key.
28+
RNCryptor uses either a 256-bit random key or a password. It extracts a 512-bit
29+
pseudorandom key (PRK) from this using HKDF-Extract or PBKDF2. It then uses
30+
HKDF-Expand to expand this key material into the IV, a validation token, the
31+
encryption key, and the HMAC key.
2632

2733
## Key Validation
2834

2935
Using the validation token, the encryption key can be tested without validating HMAC.
3036

3137
## Implementation Procedure
3238

33-
Unless otherwise noted, all example implementations are given in an abtract, idealized language. It includes the following constructs:
39+
Unless otherwise noted, all example implementations are given in an abtract,
40+
idealized language. It includes the following constructs:
3441

3542
* `||` - Operator that concatenates two octet strings.
3643
* `RandomDataOfLength(n)` - Returns `n` random octets generated by a [CSPRNG](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator).
@@ -46,76 +53,91 @@ Unless otherwise noted, all example implementations are given in an abtract, ide
4653
* `SHA512` - Token indicating SHA-2 hash function with 512-bit length.
4754
* `CBCMode` - Token indicating [cipher block chaining (CBC)](https://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29) block cipher mode. This implicitly includes PKCS#7 padding.
4855

56+
## Key HKDF-expansion
57+
58+
Expand PRK to 96 bytes for required material using HMAC-SHA-512 + HMAC-SHA-512-256.
59+
60+
```
61+
def Expand(prk[64]) =
62+
info = "rncryptor"
63+
T1 = HMAC(SHA512, prk, info || 0x01, 512 bits)
64+
T2 = HMAC(SHA512, prk, T1 || info || 0x02, 256 bits)
65+
return T1 || T2
66+
```
67+
4968
## General encryption function
5069

51-
Takes a 512-bit pseudorandom key (prk). Expands it into the validator, IV, encryption key, and HMAC key.
70+
Takes a 512-bit pseudorandom key (prk). Expands it into the encryption key,HMAC
71+
key, IV, and validator. Validator is last so attacker cannot short-cut
72+
Expand().
5273

5374
```
5475
def Encrypt(prk[64], options[1], salt[16], plaintext) =
55-
// HKDF-Expand
56-
(validator[16], iv[16]) = HMAC(SHA512, prk, "rncryptor.validator+iv" || 0x01, 256 bits)
57-
(encryptionKey[32], hmacKey[32]) = HMAC(SHA512, prk, "rncryptor.keys" || 0x01, 512 bits)
76+
(encryptionKey[32], hmacKey[32], iv[16], validator[16]) = Expand(prk)
5877
5978
version = 0x04
60-
header = version[1] || options[1] || salt[16] || validator[16]
61-
headerBitLength = 272LL
79+
header = version || options || salt || validator
6280
ciphertext = AESEncrypt(256 bits, CBCMode, encryptionKey, iv, plaintext)
63-
hmac = HMAC(SHA512, hmacKey, header || ciphertext || headerBitLength, 256 bits)
81+
hmac = HMAC(SHA512, hmacKey, header || ciphertext, 256 bits)
6482
return header || ciphertext || hmac
6583
```
6684

67-
1. Expand PRK into validator and IV
68-
2. Expand PRK into encryption key and HMAC key
69-
3. Construct header from version, options, salt, and validator
70-
4. Note length of header in bits
71-
5. Encrypt ciphertext with AES-256
72-
6. Compute HMAC with SHA-512, truncated to 256 bits
73-
7. Return message with header, ciphertext, and HMAC
85+
1. Expand PRK into validator, IV, and keys
86+
2. Construct header from version, options, salt, and validator
87+
3. Encrypt ciphertext with AES-256
88+
4. Compute HMAC with SHA-512-256
89+
5. Return message with header, ciphertext, and HMAC
7490

7591
## General decryption function
7692

7793
```
7894
def Decrypt(prk[64], options[1], salt[16], validator[16], ciphertext, hmac[32]) =
79-
// HKDF-Expand
80-
(expectedValidator[16], iv[16]) = HMAC(SHA512, prk, "rncryptor.validator+iv" || 0x01, 256 bits)
95+
(encryptionKey[32], hmacKey[32], iv[16], validator[16]) = Expand(prk)
8196
if (! ConsistentTimeEqual(expectedValidator, validator) return KEY_MISMATCH
8297
83-
(encryptionKey, hmacKey) = HMAC(SHA512, prk, "rncryptor.keys" || 0x01, 512 bits)
84-
8598
version = 0x04
8699
header = version || options || salt || validator
87-
headerBitLength = 272LL
88-
expectedHmac = HMAC(SHA512, hmacKey, header || ciphertext || headerBitLength, 256 bits)
100+
expectedHmac = HMAC(SHA512, hmacKey, header || ciphertext, 256 bits)
89101
90102
if ! ConsistentTimeEqual(expectedHmac, hmac) return CORRUPT
91103
else return AESDecrypt(2556 bits, CBCMode, encryptionKey, iv, ciphertext)
92104
```
93105

94-
1. Expand PRK into an expected validator and IV.
106+
1. Expand PRK into validator, IV, and keys
95107
2. Verify (in constant time) that validators match. If not, the password was incorrect.
96-
3. Expand PRK into encryption key and HMAC key.
97-
4. Construct header from version, options, salt, and validator.
98-
5. Note length of header in bits.
99-
6. Compute expected HMAC with SHA-512, truncated to 256 bit.
100-
7. Verify (in constant time) that HMACs match. If not, the ciphertext is corrupt.
101-
8. Return decrypted data.
108+
3. Construct header from version, options, salt, and validator.
109+
4. Compute expected HMAC with SHA-512-256
110+
5. Verify (in constant time) that HMACs match. If not, the ciphertext is corrupt.
111+
6. Return decrypted data.
102112

103113
## Key-based encryption
104114

115+
Input is 256 random bits of source keying material (called `key`). To maintain
116+
consistency with PBKDF2, and to improve poorly generated keys (key reuse or
117+
non-random key selection), the actual pseudorandom key (PRK) is extracted with
118+
HKDF and a 128-bit random salt.
119+
120+
Note that SHA-1 is used (rather than SHA-2) to maintain better platform
121+
support. .NET's Rfc2898DeriveBytes only supports SHA1HMAC. There is no security
122+
concern in using SHA-1 here. PBKDF2 only requires a PRF to maintain itssecurity
123+
proof, and SHA-1, even with its known attacks, continues to be a PRF. Hopefully
124+
.NET will eventually support SHA-2 PBKDF2 and we'll be able to drop SHA-1 as a
125+
matter of housekeeping (minimizing the number of algorithms required).
126+
105127
```
106128
def KeyBasedEncrypt(key[32], plaintext) =
107129
salt = RandomDataOfLength(16 bytes)
108130
109131
// HKDF-Extract
110-
prk = HMAC(SHA512, salt, key, 512 bits)
132+
prk = HMAC(SHA1, salt, key, 512 bits)
111133
112134
options = 0
113135
114136
return Encrypt(prk, options, salt, plaintext)
115137
```
116138

117139
1. Generate random salt.
118-
2. Extract 512-bit PRK from 32-bit key via HKDF.
140+
2. Extract 512-bit PRK from 256-bit key + 128-bit salt via HKDF.
119141
3. Perform generic encryption.
120142

121143
## Key-based Decryption
@@ -193,9 +215,16 @@ def PasswordBasedDecrypt(password, message) =
193215

194216
## Consistent-time equality checking
195217

196-
When comparing the computed HMAC with the expected HMAC, it is important that your comparison be made in consistent time. Your comparison function should compare all of the bytes of the ExpectedHMAC, even if it finds a mismatch. Otherwise, your comparison can be subject to a timing attack, where the attacker sends you different HMACs and times how long it takes you to return that they are not equal. Using this, the attacker can progressively determine each byte of the HMAC.
218+
When comparing the computed HMAC with the expected HMAC, it is important that
219+
your comparison be made in consistent time. Your comparison function should
220+
compare all of the bytes of the ExpectedHMAC, even if it finds a mismatch.
221+
Otherwise, your comparison can be subject to a timing attack, where the
222+
attacker sends you different HMACs and times how long it takes you to return
223+
that they are not equal. Using this, the attacker can progressively determine
224+
each byte of the HMAC.
197225

198226
Here is an example consistent-time equality function in ObjC:
227+
199228
``` objc
200229
- (BOOL)rnc_isEqualInConsistentTime:(NSData *)otherData {
201230
// The point of this routine is XOR the bytes of each data and accumulate the results with OR.
@@ -219,18 +248,26 @@ Here is an example consistent-time equality function in ObjC:
219248

220249
## Approach and Notes
221250

222-
RNCryptor is very similar to [draft-mcgrew-aead-aes-cbc-hmac-sha2](https://tools.ietf.org/id/draft-mcgrew-aead-aes-cbc-hmac-sha2-02.html) AEAD_AES_256_CBC_HMAC_SHA_512 in how it produces authenticated encryption from AES-CBC and HMAC-SHA. It differs slightly in how it generates the keys (via HKDF rather than splitting the PRK), and it computes the IV via HKDF rather than passing a random IV.
251+
RNCryptor is similar to
252+
[draft-mcgrew-aead-aes-cbc-hmac-sha2](https://tools.ietf.org/id/draft-mcgrew-aead-aes-cbc-hmac-sha2-02.html)
253+
AEAD_AES_256_CBC_HMAC_SHA_512 in how it produces authenticated encryption from
254+
AES-CBC and HMAC-SHA. It differs slightly in how it generates the keys (via
255+
HKDF rather than splitting the PRK), and it computes the IV via HKDF rather
256+
than passing a random IV.
223257

224-
RNCryptor relies on HKDF ([RFC 5869](https://tools.ietf.org/html/rfc5869)) to generate random octet strings from a master 512-bit PRK.
258+
RNCryptor relies on HKDF ([RFC 5869](https://tools.ietf.org/html/rfc5869)) to
259+
generate random octet strings from a master 512-bit PRK.
225260

226-
RNCryptor makes an effort to minimize the number of cryptographic primitives required. In particular, SHA-512 is used in some places that SHA-256 could be sufficient.
261+
The HMAC is are truncated according to [RFC 2104 Section
262+
5](https://tools.ietf.org/html/rfc2104). Private HMACs are not truncated.
227263

228-
The HMAC is truncated to 256 bits in accordance with AEAD_AES_256_CBC_HMAC_SHA_512.
264+
SHA-512 is used throughout to favor CPU rather than GPU performance.
229265

230-
## Changes since version 3.1
266+
## Changes since version 3.0
231267

232268
* Employs draft-mcgrew-aead-aes-cbc-hmac-sha2 and HKDF.
233269
* Computes IV and keys from salt and master key.
234270
* Adds validator for fast password checking
235271
* Replaces SHA-1 and SHA-256 with SHA-512.
236-
* Unifies key- and password-based formats.
272+
* Unifies key- and password-based formats.
273+

0 commit comments

Comments
 (0)