1 /**
  2  *  ---------
  3  * |.##> <##.|  SmartCard-HSM Support Scripts
  4  * |#       #|
  5  * |#       #|  Copyright (c) 2011-2012 CardContact Software & System Consulting
  6  * |'##> <##'|  Andreas Schwier, 32429 Minden, Germany (www.cardcontact.de)
  7  *  ---------
  8  *
  9  *  This file is part of OpenSCDP.
 10  *
 11  *  OpenSCDP is free software; you can redistribute it and/or modify
 12  *  it under the terms of the GNU General Public License version 2 as
 13  *  published by the Free Software Foundation.
 14  *
 15  *  OpenSCDP is distributed in the hope that it will be useful,
 16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18  *  GNU General Public License for more details.
 19  *
 20  *  You should have received a copy of the GNU General Public License
 21  *  along with OpenSCDP; if not, write to the Free Software
 22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 23  *
 24  * @fileoverview DKEK key wrapper
 25  */
 26 
 27 
 28 
 29 /**
 30  * Class supporting DKEK functions outside the SmartCard-HSM
 31  *
 32  * @constructor
 33  * @param {Crypto} crypto the crypto provider
 34  */
 35 function DKEK(crypto) {
 36 	this.crypto = crypto;
 37 	this.dkek = new ByteString("0000000000000000000000000000000000000000000000000000000000000000", HEX);
 38 }
 39 
 40 exports.DKEK = DKEK;
 41 
 42 
 43 
 44 /**
 45  * Import a DKEK share
 46  *
 47  * @param {ByteString} share a 32 byte share
 48  */
 49 DKEK.prototype.importDKEKShare = function(share) {
 50 	assert(share instanceof ByteString, "Share must be of type ByteString");
 51 	assert(share.length == 32, "Share must be 32 byte long");
 52 	var ndkek = this.dkek.xor(share);
 53 	this.dkek.clear();
 54 	this.dkek = ndkek;
 55 }
 56 
 57 
 58 
 59 /**
 60  * Zeroize DKEK
 61  *
 62  */
 63 DKEK.prototype.clear = function() {
 64 	this.dkek.clear();
 65 }
 66 
 67 
 68 
 69 /**
 70  * Return the Key Check Value (KCV) of the internal DKEK
 71  *
 72  * @type ByteString
 73  * @return the KCV
 74  */
 75 DKEK.prototype.getKCV = function() {
 76 	return this.crypto.digest(Crypto.SHA_256, this.dkek).left(8);
 77 }
 78 
 79 
 80 
 81 /**
 82  * Derive the encryption key from the DKEK
 83  *
 84  * @type ByteString
 85  * @return the encryption key
 86  */
 87 DKEK.prototype.getKENC = function() {
 88 	var kencval = this.crypto.digest(Crypto.SHA_256, this.dkek.concat(new ByteString("00000001", HEX)));
 89 	var kenc = new Key();
 90 	kenc.setComponent(Key.AES, kencval);
 91 	return kenc;
 92 }
 93 
 94 
 95 
 96 /**
 97  * Derive the message authentication key from the DKEK
 98  *
 99  * @type ByteString
100  * @return the message authentication key
101  */
102 DKEK.prototype.getKMAC = function() {
103 	var kmacval = this.crypto.digest(Crypto.SHA_256, this.dkek.concat(new ByteString("00000002", HEX)));
104 	var kmac = new Key();
105 	kmac.setComponent(Key.AES, kmacval);
106 	return kmac;
107 }
108 
109 
110 
111 /**
112  * Derive DKEK share encryption key from password
113  *
114  * @param {ByteString} password the password
115  * @type ByteString
116  * @return the derived key (32 Byte) concatenated with the IV (16 Byte)
117  */
118 DKEK.deriveDKEKShareKey = function(salt, password) {
119 	var crypto = new Crypto();
120 
121 	var d = new ByteString("", HEX);
122 	var keyivbuff = new ByteBuffer(48);
123 
124 	for (j = 0; j < 3; j++) {
125 		print("Derive DKEK share encryption key (Step " + (j + 1) + " of 3)...");
126 		var nd = d.concat(password);
127 		d.clear();
128 		d = nd;
129 
130 		var nd = d.concat(salt);
131 		d.clear();
132 		d = nd;
133 
134 		try	{
135 			// Try the fast hash available in scdp4j 3.8
136 			var h = crypto.digest(Crypto.MD5, d, 10000000);
137 			d.clear();
138 			d = h;
139 		}
140 		catch(e) {
141 			// Fallback to slow variant
142 			for (var i = 10000000; i > 0; i--) {
143 				d = crypto.digest(Crypto.MD5, d);
144 			}
145 		}
146 		keyivbuff.append(d);
147 	}
148 
149 	var keyiv = keyivbuff.toByteString();
150 	keyivbuff.clear();
151 	return keyiv;
152 }
153 
154 
155 
156 /**
157  * Encrypt a DKEK share
158  *
159  * @param {ByteString} keyshare the key share
160  * @param {ByteString} password the password
161  * @type ByteString
162  * @return Encrypted DKEK share value
163  */
164 DKEK.encryptKeyShare = function(keyshare, password) {
165 	assert(keyshare instanceof ByteString, "Argument keyshare must be ByteString");
166 	assert(keyshare.length == 32, "Argument keyshare must be 32 bytes");
167 	assert(password instanceof ByteString, "Argument password must be ByteString");
168 
169 	var crypto = new Crypto();
170 	var salt = crypto.generateRandom(8);
171 
172 	var keyiv = DKEK.deriveDKEKShareKey(salt, password);
173 
174 	var k = new Key();
175 	k.setComponent(Key.AES, keyiv.bytes(0, 32));
176 	var iv = keyiv.bytes(32, 16);
177 	keyiv.clear();
178 
179 	var plain = keyshare.concat(new ByteString("10101010101010101010101010101010", HEX));
180 	var cipher = crypto.encrypt(k, Crypto.AES_CBC, plain, iv);
181 	plain.clear();
182 	k.getComponent(Key.AES).clear();
183 
184 	var blob = (new ByteString("Salted__", ASCII)).concat(salt).concat(cipher);
185 	return blob;
186 }
187 
188 
189 
190 /**
191  * Decrypt a DKEK share
192  *
193  * @param {ByteString} keyshare the encrypted key share as read from the .pbe file
194  * @param {ByteString} password the password
195  * @type ByteString
196  * @return plain DKEK value
197  */
198 DKEK.decryptKeyShare = function(keyshare, password) {
199 	assert(password instanceof ByteString, "Argument password must be ByteString");
200 	if ((keyshare.length != 64) || !keyshare.bytes(0, 8).toString(ASCII).equals("Salted__")) {
201 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Does not seem to be an encrypted key share");
202 	}
203 
204 	var crypto = new Crypto();
205 	var salt = keyshare.bytes(8, 8);
206 
207 	var keyiv = DKEK.deriveDKEKShareKey(salt, password);
208 
209 	var k = new Key();
210 	k.setComponent(Key.AES, keyiv.bytes(0, 32));
211 	var iv = keyiv.bytes(32, 16);
212 	keyiv.clear();
213 
214 	var plain = crypto.decrypt(k, Crypto.AES_CBC, keyshare.bytes(16), iv);
215 	k.getComponent(Key.AES).clear();
216 
217 	if (!(new ByteString("10101010101010101010101010101010", HEX)).equals(plain.right(16))) {
218 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Decryption of DKEK failed. Wrong password ?");
219 	}
220 
221 	var val = plain.left(32);
222 	plain.clear();
223 
224 	return val;
225 }
226 
227 
228 
229 /**
230  * Test DKEK share encryption / decryption
231  *
232  * @private
233  */
234 DKEK.testDKEK = function() {
235 	var crypto = new Crypto();
236 	var dkek = crypto.generateRandom(32);
237 	var password = new ByteString("Password", ASCII);
238 	var enc = DKEK.encryptKeyShare(dkek, password);
239 	print(enc);
240 	var plain = DKEK.decryptKeyShare(enc, password);
241 	assert(dkek.equals(plain), "Reference does not match");
242 }
243 
244 
245 
246 /**
247  * Wrap AES key
248  *
249  * @param {Key} key the secret key
250  * @type ByteString
251  * @return the secret key wrapped with the DKEK
252  */
253 DKEK.prototype.encodeAESKey = function(key) {
254 	var bb = new ByteBuffer();
255 	bb.append(this.getKCV());
256 
257 	assert(key.getType() == Key.SECRET)
258 
259 	bb.append(15);
260 
261 	var daid = new ByteString("2.16.840.1.101.3.4.1", OID);
262 	bb.append(ByteString.valueOf(daid.length, 2));
263 	bb.append(daid);
264 
265 	var aaid = new ByteString("10 11 18 99", HEX);
266 	bb.append(ByteString.valueOf(aaid.length, 2));
267 	bb.append(aaid);
268 
269 	bb.append(ByteString.valueOf(0, 2));
270 	bb.append(ByteString.valueOf(0, 2));
271 
272 	var kb = new ByteBuffer(256);
273 	kb.append(this.crypto.generateRandom(8));
274 
275 	kb.append(ByteString.valueOf(key.getSize() / 8, 2));
276 	kb.append(key.getComponent(Key.AES));
277 
278 	var unpadded = kb.toByteString();
279 	var plain = unpadded.pad(Crypto.ISO9797_METHOD_2);
280 	unpadded.clear();
281 
282 	if (plain.length & 0xF) {		// pad() padds to 8 byte blocks, but we 16 byte blocks
283 		var nplain = plain.concat(new ByteString("0000000000000000", HEX));
284 		plain.clear();
285 		plain = nplain;
286 	}
287 
288 	var iv = new ByteString("00000000000000000000000000000000", HEX);
289 	var kenc = this.getKENC();
290 	var cipher = this.crypto.encrypt(kenc, Crypto.AES_CBC, plain, iv);
291 	kenc.getComponent(Key.AES).clear();
292 	plain.clear();
293 
294 	bb.append(cipher);
295 
296 	var kmac = this.getKMAC();
297 	bb.append(this.crypto.sign(kmac, Crypto.AES_CMAC, bb.toByteString()));
298 	kmac.getComponent(Key.AES).clear();
299 
300 	return bb.toByteString();
301 }
302 
303 
304 
305 /**
306  * Wrap RSA or ECC key
307  *
308  * @param {Key} pri the private key in CRT format
309  * @param {Key} pub the public key
310  * @type Key
311  * @return the private key in private exponent / modulus format
312  */
313 DKEK.prototype.convertCRT2PEM = function(pri, pub) {
314 	var n = pub.getComponent(Key.MODULUS);
315 	var r = ByteString.valueOf(0).concat(n);
316 	r = r.sub(ByteString.valueOf(0).concat(pri.getComponent(Key.CRT_P)));
317 	r = r.sub(ByteString.valueOf(0).concat(pri.getComponent(Key.CRT_Q)));
318 	r = r.biAdd(ByteString.valueOf(1));
319 	var e = pub.getComponent(Key.EXPONENT);
320 	var d = e.modInverse(r);
321 
322 	// Strip leading zero in private exponent
323 	if (d.byteAt(0) == 0) {
324 		d = d.bytes(1);
325 	}
326 
327 	var nk = new Key();
328 	nk.setType(Key.PRIVATE);
329 	nk.setComponent(Key.MODULUS, n);
330 	nk.setComponent(Key.EXPONENT, d);
331 	return nk;
332 }
333 
334 
335 
336 /**
337  * Wrap RSA or ECC key
338  *
339  * @param {Key} pri the private key
340  * @param {Key} pub the public key
341  * @type ByteString
342  * @return the private key wrapped with the DKEK
343  */
344 DKEK.prototype.encodeKey = function(pri, pub) {
345 	var bb = new ByteBuffer();
346 	bb.append(this.getKCV());
347 
348 	var mod = pub.getComponent(Key.MODULUS);
349 	if (mod) {
350 		// Convert RSA keys larger than 2048 bit and in CRT format
351 		if ((mod.length > 256) && pri.getComponent(Key.CRT_P)) {
352 			pri = this.convertCRT2PEM(pri, pub);
353 		}
354 		if (pri.getComponent(Key.CRT_P)) {
355 			bb.append(6);
356 		} else {
357 			bb.append(5);
358 		}
359 		var algo = new ByteString("id-TA-RSA-v1-5-SHA-256", OID);
360 	} else {
361 		bb.append(12);
362 		var algo = new ByteString("id-TA-ECDSA-SHA-256", OID);
363 	}
364 
365 	bb.append(ByteString.valueOf(algo.length, 2));
366 	bb.append(algo);
367 
368 	bb.append(ByteString.valueOf(0, 2));
369 	bb.append(ByteString.valueOf(0, 2));
370 	bb.append(ByteString.valueOf(0, 2));
371 
372 	var kb = new ByteBuffer(4096);
373 	kb.append(this.crypto.generateRandom(8));
374 
375 	if (pub.getComponent(Key.MODULUS)) {
376 		kb.append(ByteString.valueOf(pub.getComponent(Key.MODULUS).length << 3, 2));
377 
378 		if (pri.getComponent(Key.CRT_P)) {
379 			var c = pri.getComponent(Key.CRT_DP1);
380 			kb.append(ByteString.valueOf(c.length, 2));
381 			kb.append(c);
382 
383 			var c = pri.getComponent(Key.CRT_DQ1);
384 			kb.append(ByteString.valueOf(c.length, 2));
385 			kb.append(c);
386 
387 			var c = pri.getComponent(Key.CRT_P);
388 			kb.append(ByteString.valueOf(c.length, 2));
389 			kb.append(c);
390 
391 			var c = pri.getComponent(Key.CRT_PQ);
392 			kb.append(ByteString.valueOf(c.length, 2));
393 			kb.append(c);
394 
395 			var c = pri.getComponent(Key.CRT_Q);
396 			kb.append(ByteString.valueOf(c.length, 2));
397 			kb.append(c);
398 		} else {
399 			var c = pri.getComponent(Key.EXPONENT);
400 			kb.append(ByteString.valueOf(c.length, 2));
401 			kb.append(c);
402 		}
403 
404 		var c = pub.getComponent(Key.MODULUS);
405 		kb.append(ByteString.valueOf(c.length, 2));
406 		kb.append(c);
407 
408 		var c = pub.getComponent(Key.EXPONENT);
409 		kb.append(ByteString.valueOf(c.length, 2));
410 		kb.append(c);
411 	} else {
412 		kb.append(ByteString.valueOf(pub.getComponent(Key.ECC_P).length << 3, 2));
413 
414 		var c = pri.getComponent(Key.ECC_A);
415 		kb.append(ByteString.valueOf(c.length, 2));
416 		kb.append(c);
417 
418 		var c = pri.getComponent(Key.ECC_B);
419 		kb.append(ByteString.valueOf(c.length, 2));
420 		kb.append(c);
421 
422 		var c = pri.getComponent(Key.ECC_P);
423 		kb.append(ByteString.valueOf(c.length, 2));
424 		kb.append(c);
425 
426 		var c = pri.getComponent(Key.ECC_N);
427 		kb.append(ByteString.valueOf(c.length, 2));
428 		kb.append(c);
429 
430 		var c = (new ByteString("04", HEX)).concat(pri.getComponent(Key.ECC_GX)).concat(pri.getComponent(Key.ECC_GY));
431 		kb.append(ByteString.valueOf(c.length, 2));
432 		kb.append(c);
433 
434 		var c = pri.getComponent(Key.ECC_D);
435 		kb.append(ByteString.valueOf(c.length, 2));
436 		kb.append(c);
437 
438 		var c = (new ByteString("04", HEX)).concat(pub.getComponent(Key.ECC_QX)).concat(pub.getComponent(Key.ECC_QY));
439 		kb.append(ByteString.valueOf(c.length, 2));
440 		kb.append(c);
441 	}
442 
443 	var unpadded = kb.toByteString();
444 	var plain = unpadded.pad(Crypto.ISO9797_METHOD_2);
445 	unpadded.clear();
446 
447 	if (plain.length & 0xF) {		// pad() padds to 8 byte blocks, but we 16 byte blocks
448 		var nplain = plain.concat(new ByteString("0000000000000000", HEX));
449 		plain.clear();
450 		plain = nplain;
451 	}
452 	// print(plain);
453 
454 	var iv = new ByteString("00000000000000000000000000000000", HEX);
455 	var kenc = this.getKENC();
456 	var cipher = this.crypto.encrypt(kenc, Crypto.AES_CBC, plain, iv);
457 	kenc.getComponent(Key.AES).clear();
458 	plain.clear();
459 
460 	bb.append(cipher);
461 
462 	var kmac = this.getKMAC();
463 	bb.append(this.crypto.sign(kmac, Crypto.AES_CMAC, bb.toByteString()));
464 	kmac.getComponent(Key.AES).clear();
465 
466 //	this.dumpKeyBLOB(bb.toByteString());
467 	return bb.toByteString();
468 }
469 
470 DKEK.prototype.encodeRSAKey = DKEK.prototype.encodeKey;
471 
472 
473 
474 DKEK.prototype.dumpKeyBLOB = function(keyblob) {
475 	// Verify MAC on last 16 byte of blob
476 
477 	var macok = this.crypto.verify(this.getKMAC(), Crypto.AES_CMAC, keyblob.bytes(0, keyblob.length - 16), keyblob.right(16));
478 
479 	var keytype = keyblob.byteAt(8);
480 	print("Values from key blob:");
481 	print("---------------------");
482 	print("Checking the MAC      : " + (macok ? "Passed" : "Failed"));
483 	print("KCV                   : " + keyblob.bytes(0, 8).toString(HEX) + "    [Must match the KCV of the DKEK for import]");
484 	print("Key type              : " + keytype + "    [5=RSA, 6=RSA-CRT, 12=ECC, 15=AES]");
485 
486 	var ofs = 9;
487 	var len = keyblob.bytes(ofs, 2).toUnsigned();
488 
489 	if ((keytype == 15) && (keyblob.byteAt(ofs + 2) != 0x60)) {
490 		print("Default Algorithm ID  : " + keyblob.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")     [Wrong encoding in V3.0 to V3.2]");
491 	} else {
492 		print("Default Algorithm ID  : " + keyblob.bytes(ofs + 2, len).toString(OID) + " (" + len + ")     [Default algorithm]");
493 	}
494 
495 	ofs += len + 2;
496 	var len = keyblob.bytes(ofs, 2).toUnsigned();
497 
498 	print("Allowed Algorithm IDs : " + keyblob.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
499 
500 	ofs += len + 2;
501 	var len = keyblob.bytes(ofs, 2).toUnsigned();
502 
503 	print("Access Conditions     : " + keyblob.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")    [Not used]");
504 
505 	ofs += len + 2;
506 	var len = keyblob.bytes(ofs, 2).toUnsigned();
507 
508 	print("Key OID               : " + keyblob.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")    [Not used]");
509 
510 	ofs += len + 2;
511 
512 
513 	// Decrypt key data
514 
515 	var iv = new ByteString("00000000000000000000000000000000", HEX);
516 	var plainkey = this.crypto.decrypt(this.getKENC(), Crypto.AES_CBC, keyblob.bytes(ofs, keyblob.length - 16 - ofs), iv);
517 	// print(plainkey);
518 
519 	print("Randomize             : " + plainkey.bytes(0, 8).toString(HEX) + "    [Random data prepended at export]");
520 
521 	var keysize = plainkey.bytes(8, 2).toUnsigned();
522 	print("Key size              : " + keysize + "    [Key size in bits (ECC/RSA) or bytes (AES)]");
523 
524 	var ofs = 10;
525 
526 	if (keytype == 5) {
527 		var len = plainkey.bytes(ofs, 2).toUnsigned();
528 
529 		print("Private Exponent      : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
530 
531 		ofs += len + 2;
532 		var len = plainkey.bytes(ofs, 2).toUnsigned();
533 
534 		print("Modulus               : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
535 
536 		ofs += len + 2;
537 		var len = plainkey.bytes(ofs, 2).toUnsigned();
538 
539 		print("Public Exponent       : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
540 	} else if (keytype == 6) {
541 		var len = plainkey.bytes(ofs, 2).toUnsigned();
542 
543 		print("DP1 = d mod (p - 1)   : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
544 
545 		ofs += len + 2;
546 		var len = plainkey.bytes(ofs, 2).toUnsigned();
547 
548 		print("DQ1 = d mod (q - 1)   : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
549 
550 		ofs += len + 2;
551 		var len = plainkey.bytes(ofs, 2).toUnsigned();
552 
553 		print("Prime factor p        : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
554 
555 		ofs += len + 2;
556 		var len = plainkey.bytes(ofs, 2).toUnsigned();
557 
558 		print("PQ = q - 1 mod p      : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
559 
560 		ofs += len + 2;
561 		var len = plainkey.bytes(ofs, 2).toUnsigned();
562 
563 		print("Prime factor q        : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
564 
565 		ofs += len + 2;
566 		var len = plainkey.bytes(ofs, 2).toUnsigned();
567 
568 		print("Modulus               : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
569 
570 		ofs += len + 2;
571 		var len = plainkey.bytes(ofs, 2).toUnsigned();
572 
573 		print("Public Exponent       : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
574 	} else if (keytype == 12) {
575 		var len = plainkey.bytes(ofs, 2).toUnsigned();
576 
577 		print("A                     : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
578 
579 		ofs += len + 2;
580 		var len = plainkey.bytes(ofs, 2).toUnsigned();
581 
582 		print("B                     : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
583 
584 		ofs += len + 2;
585 		var len = plainkey.bytes(ofs, 2).toUnsigned();
586 
587 		print("Prime factor P        : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
588 
589 		ofs += len + 2;
590 		var len = plainkey.bytes(ofs, 2).toUnsigned();
591 
592 		print("Order                 : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
593 
594 		ofs += len + 2;
595 		var len = plainkey.bytes(ofs, 2).toUnsigned();
596 
597 		print("Generator G           : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
598 
599 		ofs += len + 2;
600 		var len = plainkey.bytes(ofs, 2).toUnsigned();
601 
602 		print("Secret D              : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
603 
604 		ofs += len + 2;
605 		var len = plainkey.bytes(ofs, 2).toUnsigned();
606 
607 		print("Public Point Q        : " + plainkey.bytes(ofs + 2, len).toString(HEX) + " (" + len + ")");
608 	} else if (keytype == 15) {
609 		print("Key Value             : " + plainkey.bytes(ofs, keysize).toString(HEX));
610 	} else {
611 		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Unknown key type " + keytype);
612 	}
613 }
614