source: trip-planner-front/node_modules/node-forge/lib/aesCipherSuites.js@ 1ad8e64

Last change on this file since 1ad8e64 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 8.9 KB
RevLine 
[6a3a178]1/**
2 * A Javascript implementation of AES Cipher Suites for TLS.
3 *
4 * @author Dave Longley
5 *
6 * Copyright (c) 2009-2015 Digital Bazaar, Inc.
7 *
8 */
9var forge = require('./forge');
10require('./aes');
11require('./tls');
12
13var tls = module.exports = forge.tls;
14
15/**
16 * Supported cipher suites.
17 */
18tls.CipherSuites['TLS_RSA_WITH_AES_128_CBC_SHA'] = {
19 id: [0x00, 0x2f],
20 name: 'TLS_RSA_WITH_AES_128_CBC_SHA',
21 initSecurityParameters: function(sp) {
22 sp.bulk_cipher_algorithm = tls.BulkCipherAlgorithm.aes;
23 sp.cipher_type = tls.CipherType.block;
24 sp.enc_key_length = 16;
25 sp.block_length = 16;
26 sp.fixed_iv_length = 16;
27 sp.record_iv_length = 16;
28 sp.mac_algorithm = tls.MACAlgorithm.hmac_sha1;
29 sp.mac_length = 20;
30 sp.mac_key_length = 20;
31 },
32 initConnectionState: initConnectionState
33};
34tls.CipherSuites['TLS_RSA_WITH_AES_256_CBC_SHA'] = {
35 id: [0x00, 0x35],
36 name: 'TLS_RSA_WITH_AES_256_CBC_SHA',
37 initSecurityParameters: function(sp) {
38 sp.bulk_cipher_algorithm = tls.BulkCipherAlgorithm.aes;
39 sp.cipher_type = tls.CipherType.block;
40 sp.enc_key_length = 32;
41 sp.block_length = 16;
42 sp.fixed_iv_length = 16;
43 sp.record_iv_length = 16;
44 sp.mac_algorithm = tls.MACAlgorithm.hmac_sha1;
45 sp.mac_length = 20;
46 sp.mac_key_length = 20;
47 },
48 initConnectionState: initConnectionState
49};
50
51function initConnectionState(state, c, sp) {
52 var client = (c.entity === forge.tls.ConnectionEnd.client);
53
54 // cipher setup
55 state.read.cipherState = {
56 init: false,
57 cipher: forge.cipher.createDecipher('AES-CBC', client ?
58 sp.keys.server_write_key : sp.keys.client_write_key),
59 iv: client ? sp.keys.server_write_IV : sp.keys.client_write_IV
60 };
61 state.write.cipherState = {
62 init: false,
63 cipher: forge.cipher.createCipher('AES-CBC', client ?
64 sp.keys.client_write_key : sp.keys.server_write_key),
65 iv: client ? sp.keys.client_write_IV : sp.keys.server_write_IV
66 };
67 state.read.cipherFunction = decrypt_aes_cbc_sha1;
68 state.write.cipherFunction = encrypt_aes_cbc_sha1;
69
70 // MAC setup
71 state.read.macLength = state.write.macLength = sp.mac_length;
72 state.read.macFunction = state.write.macFunction = tls.hmac_sha1;
73}
74
75/**
76 * Encrypts the TLSCompressed record into a TLSCipherText record using AES
77 * in CBC mode.
78 *
79 * @param record the TLSCompressed record to encrypt.
80 * @param s the ConnectionState to use.
81 *
82 * @return true on success, false on failure.
83 */
84function encrypt_aes_cbc_sha1(record, s) {
85 var rval = false;
86
87 // append MAC to fragment, update sequence number
88 var mac = s.macFunction(s.macKey, s.sequenceNumber, record);
89 record.fragment.putBytes(mac);
90 s.updateSequenceNumber();
91
92 // TLS 1.1+ use an explicit IV every time to protect against CBC attacks
93 var iv;
94 if(record.version.minor === tls.Versions.TLS_1_0.minor) {
95 // use the pre-generated IV when initializing for TLS 1.0, otherwise use
96 // the residue from the previous encryption
97 iv = s.cipherState.init ? null : s.cipherState.iv;
98 } else {
99 iv = forge.random.getBytesSync(16);
100 }
101
102 s.cipherState.init = true;
103
104 // start cipher
105 var cipher = s.cipherState.cipher;
106 cipher.start({iv: iv});
107
108 // TLS 1.1+ write IV into output
109 if(record.version.minor >= tls.Versions.TLS_1_1.minor) {
110 cipher.output.putBytes(iv);
111 }
112
113 // do encryption (default padding is appropriate)
114 cipher.update(record.fragment);
115 if(cipher.finish(encrypt_aes_cbc_sha1_padding)) {
116 // set record fragment to encrypted output
117 record.fragment = cipher.output;
118 record.length = record.fragment.length();
119 rval = true;
120 }
121
122 return rval;
123}
124
125/**
126 * Handles padding for aes_cbc_sha1 in encrypt mode.
127 *
128 * @param blockSize the block size.
129 * @param input the input buffer.
130 * @param decrypt true in decrypt mode, false in encrypt mode.
131 *
132 * @return true on success, false on failure.
133 */
134function encrypt_aes_cbc_sha1_padding(blockSize, input, decrypt) {
135 /* The encrypted data length (TLSCiphertext.length) is one more than the sum
136 of SecurityParameters.block_length, TLSCompressed.length,
137 SecurityParameters.mac_length, and padding_length.
138
139 The padding may be any length up to 255 bytes long, as long as it results in
140 the TLSCiphertext.length being an integral multiple of the block length.
141 Lengths longer than necessary might be desirable to frustrate attacks on a
142 protocol based on analysis of the lengths of exchanged messages. Each uint8
143 in the padding data vector must be filled with the padding length value.
144
145 The padding length should be such that the total size of the
146 GenericBlockCipher structure is a multiple of the cipher's block length.
147 Legal values range from zero to 255, inclusive. This length specifies the
148 length of the padding field exclusive of the padding_length field itself.
149
150 This is slightly different from PKCS#7 because the padding value is 1
151 less than the actual number of padding bytes if you include the
152 padding_length uint8 itself as a padding byte. */
153 if(!decrypt) {
154 // get the number of padding bytes required to reach the blockSize and
155 // subtract 1 for the padding value (to make room for the padding_length
156 // uint8)
157 var padding = blockSize - (input.length() % blockSize);
158 input.fillWithByte(padding - 1, padding);
159 }
160 return true;
161}
162
163/**
164 * Handles padding for aes_cbc_sha1 in decrypt mode.
165 *
166 * @param blockSize the block size.
167 * @param output the output buffer.
168 * @param decrypt true in decrypt mode, false in encrypt mode.
169 *
170 * @return true on success, false on failure.
171 */
172function decrypt_aes_cbc_sha1_padding(blockSize, output, decrypt) {
173 var rval = true;
174 if(decrypt) {
175 /* The last byte in the output specifies the number of padding bytes not
176 including itself. Each of the padding bytes has the same value as that
177 last byte (known as the padding_length). Here we check all padding
178 bytes to ensure they have the value of padding_length even if one of
179 them is bad in order to ward-off timing attacks. */
180 var len = output.length();
181 var paddingLength = output.last();
182 for(var i = len - 1 - paddingLength; i < len - 1; ++i) {
183 rval = rval && (output.at(i) == paddingLength);
184 }
185 if(rval) {
186 // trim off padding bytes and last padding length byte
187 output.truncate(paddingLength + 1);
188 }
189 }
190 return rval;
191}
192
193/**
194 * Decrypts a TLSCipherText record into a TLSCompressed record using
195 * AES in CBC mode.
196 *
197 * @param record the TLSCipherText record to decrypt.
198 * @param s the ConnectionState to use.
199 *
200 * @return true on success, false on failure.
201 */
202function decrypt_aes_cbc_sha1(record, s) {
203 var rval = false;
204
205 var iv;
206 if(record.version.minor === tls.Versions.TLS_1_0.minor) {
207 // use pre-generated IV when initializing for TLS 1.0, otherwise use the
208 // residue from the previous decryption
209 iv = s.cipherState.init ? null : s.cipherState.iv;
210 } else {
211 // TLS 1.1+ use an explicit IV every time to protect against CBC attacks
212 // that is appended to the record fragment
213 iv = record.fragment.getBytes(16);
214 }
215
216 s.cipherState.init = true;
217
218 // start cipher
219 var cipher = s.cipherState.cipher;
220 cipher.start({iv: iv});
221
222 // do decryption
223 cipher.update(record.fragment);
224 rval = cipher.finish(decrypt_aes_cbc_sha1_padding);
225
226 // even if decryption fails, keep going to minimize timing attacks
227
228 // decrypted data:
229 // first (len - 20) bytes = application data
230 // last 20 bytes = MAC
231 var macLen = s.macLength;
232
233 // create a random MAC to check against should the mac length check fail
234 // Note: do this regardless of the failure to keep timing consistent
235 var mac = forge.random.getBytesSync(macLen);
236
237 // get fragment and mac
238 var len = cipher.output.length();
239 if(len >= macLen) {
240 record.fragment = cipher.output.getBytes(len - macLen);
241 mac = cipher.output.getBytes(macLen);
242 } else {
243 // bad data, but get bytes anyway to try to keep timing consistent
244 record.fragment = cipher.output.getBytes();
245 }
246 record.fragment = forge.util.createBuffer(record.fragment);
247 record.length = record.fragment.length();
248
249 // see if data integrity checks out, update sequence number
250 var mac2 = s.macFunction(s.macKey, s.sequenceNumber, record);
251 s.updateSequenceNumber();
252 rval = compareMacs(s.macKey, mac, mac2) && rval;
253 return rval;
254}
255
256/**
257 * Safely compare two MACs. This function will compare two MACs in a way
258 * that protects against timing attacks.
259 *
260 * TODO: Expose elsewhere as a utility API.
261 *
262 * See: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/
263 *
264 * @param key the MAC key to use.
265 * @param mac1 as a binary-encoded string of bytes.
266 * @param mac2 as a binary-encoded string of bytes.
267 *
268 * @return true if the MACs are the same, false if not.
269 */
270function compareMacs(key, mac1, mac2) {
271 var hmac = forge.hmac.create();
272
273 hmac.start('SHA1', key);
274 hmac.update(mac1);
275 mac1 = hmac.digest().getBytes();
276
277 hmac.start(null, null);
278 hmac.update(mac2);
279 mac2 = hmac.digest().getBytes();
280
281 return mac1 === mac2;
282}
Note: See TracBrowser for help on using the repository browser.