corrade-nucleus-nucleons – Blame information for rev 26

Subversion Repositories:
Rev:
Rev Author Line No. Line
22 office 1 /**
2 * Javascript implementation of RSA-KEM.
3 *
4 * @author Lautaro Cozzani Rodriguez
5 * @author Dave Longley
6 *
7 * Copyright (c) 2014 Lautaro Cozzani <lautaro.cozzani@scytl.com>
8 * Copyright (c) 2014 Digital Bazaar, Inc.
9 */
10 var forge = require('./forge');
11 require('./util');
12 require('./random');
13 require('./jsbn');
14  
15 module.exports = forge.kem = forge.kem || {};
16  
17 var BigInteger = forge.jsbn.BigInteger;
18  
19 /**
20 * The API for the RSA Key Encapsulation Mechanism (RSA-KEM) from ISO 18033-2.
21 */
22 forge.kem.rsa = {};
23  
24 /**
25 * Creates an RSA KEM API object for generating a secret asymmetric key.
26 *
27 * The symmetric key may be generated via a call to 'encrypt', which will
28 * produce a ciphertext to be transmitted to the recipient and a key to be
29 * kept secret. The ciphertext is a parameter to be passed to 'decrypt' which
30 * will produce the same secret key for the recipient to use to decrypt a
31 * message that was encrypted with the secret key.
32 *
33 * @param kdf the KDF API to use (eg: new forge.kem.kdf1()).
34 * @param options the options to use.
35 * [prng] a custom crypto-secure pseudo-random number generator to use,
36 * that must define "getBytesSync".
37 */
38 forge.kem.rsa.create = function(kdf, options) {
39 options = options || {};
40 var prng = options.prng || forge.random;
41  
42 var kem = {};
43  
44 /**
45 * Generates a secret key and its encapsulation.
46 *
47 * @param publicKey the RSA public key to encrypt with.
48 * @param keyLength the length, in bytes, of the secret key to generate.
49 *
50 * @return an object with:
51 * encapsulation: the ciphertext for generating the secret key, as a
52 * binary-encoded string of bytes.
53 * key: the secret key to use for encrypting a message.
54 */
55 kem.encrypt = function(publicKey, keyLength) {
56 // generate a random r where 1 > r > n
57 var byteLength = Math.ceil(publicKey.n.bitLength() / 8);
58 var r;
59 do {
60 r = new BigInteger(
61 forge.util.bytesToHex(prng.getBytesSync(byteLength)),
62 16).mod(publicKey.n);
63 } while(r.equals(BigInteger.ZERO));
64  
65 // prepend r with zeros
66 r = forge.util.hexToBytes(r.toString(16));
67 var zeros = byteLength - r.length;
68 if(zeros > 0) {
69 r = forge.util.fillString(String.fromCharCode(0), zeros) + r;
70 }
71  
72 // encrypt the random
73 var encapsulation = publicKey.encrypt(r, 'NONE');
74  
75 // generate the secret key
76 var key = kdf.generate(r, keyLength);
77  
78 return {encapsulation: encapsulation, key: key};
79 };
80  
81 /**
82 * Decrypts an encapsulated secret key.
83 *
84 * @param privateKey the RSA private key to decrypt with.
85 * @param encapsulation the ciphertext for generating the secret key, as
86 * a binary-encoded string of bytes.
87 * @param keyLength the length, in bytes, of the secret key to generate.
88 *
89 * @return the secret key as a binary-encoded string of bytes.
90 */
91 kem.decrypt = function(privateKey, encapsulation, keyLength) {
92 // decrypt the encapsulation and generate the secret key
93 var r = privateKey.decrypt(encapsulation, 'NONE');
94 return kdf.generate(r, keyLength);
95 };
96  
97 return kem;
98 };
99  
100 // TODO: add forge.kem.kdf.create('KDF1', {md: ..., ...}) API?
101  
102 /**
103 * Creates a key derivation API object that implements KDF1 per ISO 18033-2.
104 *
105 * @param md the hash API to use.
106 * @param [digestLength] an optional digest length that must be positive and
107 * less than or equal to md.digestLength.
108 *
109 * @return a KDF1 API object.
110 */
111 forge.kem.kdf1 = function(md, digestLength) {
112 _createKDF(this, md, 0, digestLength || md.digestLength);
113 };
114  
115 /**
116 * Creates a key derivation API object that implements KDF2 per ISO 18033-2.
117 *
118 * @param md the hash API to use.
119 * @param [digestLength] an optional digest length that must be positive and
120 * less than or equal to md.digestLength.
121 *
122 * @return a KDF2 API object.
123 */
124 forge.kem.kdf2 = function(md, digestLength) {
125 _createKDF(this, md, 1, digestLength || md.digestLength);
126 };
127  
128 /**
129 * Creates a KDF1 or KDF2 API object.
130 *
131 * @param md the hash API to use.
132 * @param counterStart the starting index for the counter.
133 * @param digestLength the digest length to use.
134 *
135 * @return the KDF API object.
136 */
137 function _createKDF(kdf, md, counterStart, digestLength) {
138 /**
139 * Generate a key of the specified length.
140 *
141 * @param x the binary-encoded byte string to generate a key from.
142 * @param length the number of bytes to generate (the size of the key).
143 *
144 * @return the key as a binary-encoded string.
145 */
146 kdf.generate = function(x, length) {
147 var key = new forge.util.ByteBuffer();
148  
149 // run counter from counterStart to ceil(length / Hash.len)
150 var k = Math.ceil(length / digestLength) + counterStart;
151  
152 var c = new forge.util.ByteBuffer();
153 for(var i = counterStart; i < k; ++i) {
154 < k; ++i) { // I2OSP(i, 4): convert counter to an octet string of 4 octets
155 < k; ++i) { c.putInt32(i);
156  
157 < k; ++i) { // digest 'x' and the counter and add the result to the key
158 < k; ++i) { md.start();
159 < k; ++i) { md.update(x + c.getBytes());
160 < k; ++i) { var hash = md.digest();
161 < k; ++i) { key.putBytes(hash.getBytes(digestLength));
162 < k; ++i) { }
163  
164 < k; ++i) { // truncate to the correct key length
165 < k; ++i) { key.truncate(key.length() - length);
166 < k; ++i) { return key.getBytes();
167 < k; ++i) { };
168 < k; ++i) {}