      1 /**
      2  *  ---------
      3  * |.##> <##.|  Open Smart Card Development Platform (www.openscdp.org)
      4  * |#       #|
      5  * |#       #|  Copyright (c) 1999-2009 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 Basic helper functions to convert PKCS#8 data to GP keys and vice versa
     25  */
     26
     27
     28
     29 /**
     30  * Empty constructor
     31  */
     32 function PKCS8() {
     33 }
     34
     35 if (typeof(exports) != "undefined")
     36 	exports.PKCS8 = PKCS8;
     37
     38
     39 PKCS8.idEcPublicKey = new ByteString("id-ecPublicKey", OID);
     40 PKCS8.rsaEncryption = new ByteString("1.2.840.113549.1.1.1", OID);
     41
     42 /**
     43  * Convert x/y coordinates to uncompressed format
     44  *
     45  * @param {ByteString} x the x coordinate
     46  * @param {ByteString} y the y coordinate
     47  * @type ByteString
     48  * @return ByteString containing compressed format
     49  *
     50  */
     51 PKCS8.encodeUncompressedECPoint = function(x,y) {
     52
     53 	var bb = new ByteBuffer();
     54
     55 	// uncompressed encoding
     56 	bb.append(new ByteString("04", HEX));
     57 	bb.append(x);
     58 	bb.append(y);
     59
     60 	return bb.toByteString();
     61 }
     62
     63
     64
     65 /**
     66  * Convert uncompressed format to x and y coordinates
     67  *
     68  * @param {ByteString} compressed point
     69  * @type Object
     70  * @return Object with ByteString properties x and y
     71  *
     72  */
     73 PKCS8.decodeUncompressedECPoint = function(uncompressedPoint) {
     74
     75 	// Determine the size of the coordinates ignoring the indicator byte '04'
     76 	var length = uncompressedPoint.length - 1;
     77
     78 	var sizeOfCoordinate = length >> 1;
     79
     80 	var xValue = uncompressedPoint.bytes(1, sizeOfCoordinate);
     81 	var yValue = uncompressedPoint.bytes(1 + sizeOfCoordinate, sizeOfCoordinate);
     82
     83 	return { x:xValue, y:yValue };
     84 }
     85
     86
     87
     88 /**
     89  * Integer to octet string conversion
     90  *
     91  * @param {ByteString} value the encoded integer value
     92  * @param {Number} the number of digits
     93  * @type ByteString
     94  * @return the truncated or padded result
     95  */
     96 PKCS8.I2O = function(value, length) {
     97 	if (value.length > length) {
     98 		value = value.right(length);
     99 	}
    100 	while (value.length < length) {
    101 		value = PKCS8.PAD.left((length - value.length - 1 & 15) + 1).concat(value);
    102 	}
    103 	return value;
    104 }
    105 PKCS8.PAD = new ByteString("00000000000000000000000000000000", HEX);
    106
    107
    108
    109 /**
    110  * Strips leading zeros of a ByteString
    111  *
    112  * @param {ByteString} value the ByteString value
    113  * @return the stripped ByteString object, may be an empty ByteString
    114  * @type ByteString
    115  */
    116 PKCS8.stripLeadingZeros = function(value, size) {
    117 	if (typeof(size) == "undefined") {
    118 		var limit = value.length;
    119 	} else {
    120 		limit = value.length - size;
    121 	}
    122
    123 	var i = 0;
    124 	for (; (i < limit) && (value.byteAt(i) == 0); i++);
    125
    126 	return value.bytes(i);
    127 }
    128
    129
    130
    131 /**
    132  * Removes leading zeros and prepends a single '00' to ByteStrings which have the most significant bit set.
    133  *
    134  * This prevent interpretation of the integer representation if converted into
    135  * a signed ASN1 INTEGER.
    136  *
    137  * @param {ByteString} value the value to convert
    138  * @return the converted value
    139  * @type ByteString
    140  */
    141 PKCS8.convertUnsignedInteger = function(value) {
    142 	assert(value.length > 0);
    143
    144 	var i = 0;
    145 	for (; (i < value.length - 1) && (value.byteAt(i) == 0); i++);
    146
    147 	if (value.byteAt(i) >= 0x80) {
    148 		value = (new ByteString("00", HEX)).concat(value.bytes(i));
    149 	} else {
    150 		value = value.bytes(i);
    151 	}
    152
    153 	return value;
    154 }
    155
    156
    157
    158 /**
    159  * Encode a given GP ECC private key as specified by the PKCS#8 format
    160  *
    161  * @param {Key} the private key object that should be encoded
    162  * @return the encoded PKCS#8 private key
    163  * @type ByteString
    164  */
    165 PKCS8.encodeECCKeyUsingPKCS8Format = function(privateKey) {
    166 	var privateKeyInfo = new ASN1(ASN1.SEQUENCE);
    167
    168 	// Set the version number - must be zero
    169 	privateKeyInfo.add(new ASN1(ASN1.INTEGER, new ByteString("00", HEX)));
    170
    171 	var privateKeyAlgorithm = new ASN1(ASN1.SEQUENCE);
    172 	privateKeyAlgorithm.add(new ASN1(ASN1.OBJECT_IDENTIFIER, PKCS8.idEcPublicKey));
    173
    174 	var domainInfo = new ASN1(ASN1.SEQUENCE);
    175
    176 	// Cofactor - must be 1
    177 	domainInfo.add(new ASN1(ASN1.INTEGER, PKCS8.stripLeadingZeros(privateKey.getComponent(Key.ECC_H))));
    178
    179 	var field = new ASN1(ASN1.SEQUENCE);
    180
    181 	// we are using a prime field
    182 	field.add(new ASN1(ASN1.OBJECT_IDENTIFIER, new ByteString("prime-field", OID))); // prime field
    183
    184 	var primeOrder = privateKey.getComponent(Key.ECC_P);
    185 	if (primeOrder.byteAt(0) >= 0x80) { // signed int? -> add 0x00
    186 		field.add(new ASN1(ASN1.INTEGER, new ByteString("00", HEX).concat(privateKey.getComponent(Key.ECC_P))));
    187 	} else {
    188 		field.add(new ASN1(ASN1.INTEGER, privateKey.getComponent(Key.ECC_P)));
    189 	}
    190
    191 	domainInfo.add(field);
    192
    193 	// Coefficients a and b
    194 	var coeff = new ASN1(ASN1.SEQUENCE);
    195
    196 	// first coefficient
    197 	coeff.add(new ASN1(ASN1.OCTET_STRING, privateKey.getComponent(Key.ECC_A)));
    198
    199 	// second coefficient
    200 	coeff.add(new ASN1(ASN1.OCTET_STRING, privateKey.getComponent(Key.ECC_B)));
    201
    202 	domainInfo.add(coeff);
    203
    204 	// Base point (uncompressed)
    205 	var gx = privateKey.getComponent(Key.ECC_GX);
    206 	var gy = privateKey.getComponent(Key.ECC_GY);
    207
    208 	domainInfo.add(new ASN1(ASN1.OCTET_STRING, PKCS8.encodeUncompressedECPoint(gx, gy)));
    209
    210 	// group order generated by the base point
    211 	var groupOrder = privateKey.getComponent(Key.ECC_N);
    212 	if (groupOrder.byteAt(0) >= 0x80) { // signed int? -> add 0x00
    213 		domainInfo.add(new ASN1(ASN1.INTEGER, new ByteString("00", HEX).concat(privateKey.getComponent(Key.ECC_N))));
    214 	} else {
    215 		domainInfo.add(new ASN1(ASN1.INTEGER, privateKey.getComponent(Key.ECC_N)));
    216 	}
    217
    218 	privateKeyAlgorithm.add(domainInfo);
    219
    220 	// encode the key information
    221 	privateKeyInfo.add(privateKeyAlgorithm);
    222
    223 	// encode the private key
    224 	var encodedPrivateKey = new ASN1(ASN1.OCTET_STRING);
    225
    226 	var pk = privateKey.getComponent(Key.ECC_D);
    227 	var key = new ASN1(ASN1.SEQUENCE);
    228 	key.add(new ASN1(ASN1.INTEGER, new ByteString("01", HEX)));
    229 	key.add(new ASN1(ASN1.OCTET_STRING, pk));
    230
    231 	encodedPrivateKey.add(key);
    232
    233 	privateKeyInfo.add(encodedPrivateKey);
    234
    235 //	print(privateKeyInfo);
    236 	return privateKeyInfo.getBytes();
    237 }
    238
    239
    240
    241 /**
    242  * Encode RSA private key as defined in PKCS#1
    243  *
    244  * RSAPrivateKey ::= SEQUENCE {
    245  *     version           Version,
    246  *     modulus           INTEGER,  -- n
    247  *     publicExponent    INTEGER,  -- e
    248  *     privateExponent   INTEGER,  -- d
    249  *     prime1            INTEGER,  -- p
    250  *     prime2            INTEGER,  -- q
    251  *     exponent1         INTEGER,  -- d mod (p-1)
    252  *     exponent2         INTEGER,  -- d mod (q-1)
    253  *     coefficient       INTEGER,  -- (inverse of q) mod p
    254  *     otherPrimeInfos   OtherPrimeInfos OPTIONAL
    255  * }
    256  * @param {Key} privateKey the private RSA key in CRT format
    257  * @type ByteString
    258  * @return the encoded RSA key
    259  */
    260 PKCS8.encodeRSAKey = function(privateKey, publicKey) {
    261 	var rsaPrivateKey =
    262 		new ASN1(ASN1.SEQUENCE);
    263
    264 	rsaPrivateKey.add(new ASN1(ASN1.INTEGER, ByteString.valueOf(0)));
    265 	if (typeof(publicKey) != "undefined") {
    266 		rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(publicKey.getComponent(Key.MODULUS))));
    267 		rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(publicKey.getComponent(Key.EXPONENT))));
    268 	} else {
    269 		rsaPrivateKey.add(new ASN1(ASN1.INTEGER, ByteString.valueOf(0)));
    270 		rsaPrivateKey.add(new ASN1(ASN1.INTEGER, ByteString.valueOf(0)));
    271 	}
    272 	rsaPrivateKey.add(new ASN1(ASN1.INTEGER, ByteString.valueOf(0)));		// Private Exponent not at interface for CRT format
    273 	rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(privateKey.getComponent(Key.CRT_P))));
    274 	rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(privateKey.getComponent(Key.CRT_Q))));
    275 	rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(privateKey.getComponent(Key.CRT_DP1))));
    276 	rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(privateKey.getComponent(Key.CRT_DQ1))));
    277 	rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(privateKey.getComponent(Key.CRT_PQ))));
    278
    279 	return rsaPrivateKey.getBytes();
    280 }
    281
    282
    283
    284 /**
    285  * Encode a given GP RSA private key as specified by the PKCS#8 format
    286  *
    287  * @param {Key} the private key object that should be encoded
    288  * @return the encoded PKCS#8 private key
    289  * @type ByteString
    290  */
    291 PKCS8.encodeRSAKeyUsingPKCS8Format = function(privateKey, publicKey) {
    292 	var privateKeyInfo = new ASN1(ASN1.SEQUENCE);
    293
    294 	// Set the version number - must be zero
    295 	privateKeyInfo.add(new ASN1(ASN1.INTEGER, new ByteString("00", HEX)));
    296
    297 	var privateKeyAlgorithm = new ASN1(ASN1.SEQUENCE);
    298 	privateKeyAlgorithm.add(new ASN1(ASN1.OBJECT_IDENTIFIER, PKCS8.rsaEncryption));
    299 	privateKeyAlgorithm.add(new ASN1(ASN1.NULL));
    300
    301 	// encode the key information
    302 	privateKeyInfo.add(privateKeyAlgorithm);
    303
    304 	// encode the private key
    305 	var encodedPrivateKey = new ASN1(ASN1.OCTET_STRING, PKCS8.encodeRSAKey(privateKey, publicKey));
    306
    307 	privateKeyInfo.add(encodedPrivateKey);
    308
    309 //	print(privateKeyInfo);
    310 	return privateKeyInfo.getBytes();
    311 }
    312
    313
    314
    315 /**
    316  * Encode a given GP private key as specified by the PKCS#8 format
    317  *
    318  * For now we only support the encoding of ECC private keys in a prime field
    319  *
    320  * @param {Key} the private key object that should be encoded
    321  * @return the encoded PKCS#8 private key
    322  * @type ByteString
    323  */
    324 PKCS8.encodeKeyUsingPKCS8Format = function(privateKey, publicKey) {
    325
    326 	assert(privateKey.getType() == Key.PRIVATE);
    327 	if (typeof(privateKey.getComponent(Key.ECC_P)) != "undefined") {
    328 		return PKCS8.encodeECCKeyUsingPKCS8Format(privateKey);
    329 	} else {
    330 		return PKCS8.encodeRSAKeyUsingPKCS8Format(privateKey, publicKey);
    331 	}
    332 }
    333
    334
    335
    336 /**
    337  * Decode a given PKCS#8 ECC private key from the given TLV objects and create a GP key object
    338  *
    339  * For now we only support the decoding of ECC private keys in a prime field
    340  *
    341  * @param {ASN1} algparam the algorithm parameter from AlgorithmInfo
    342  * @param {ASN1} privateKey the privateKey element from the PKCS#8 structure
    343  * @return the GP key object
    344  * @type Key
    345  */
    346 PKCS8.decodeECCKeyFromPKCS8Format = function(domainParameter, encodedKey) {
    347
    348 	var key = new Key();
    349
    350 	key.setType(Key.PRIVATE);
    351
    352 	if (domainParameter.tag == ASN1.OBJECT_IDENTIFIER) {
    353 		key.setComponent(Key.ECC_CURVE_OID, domainParameter.value);
    354 	} else {
    355 		// Decode the domain parameters
    356 		var cofactor = domainParameter.get(0);
    357 		key.setComponent(Key.ECC_H, cofactor.value);
    358
    359 		var order = domainParameter.get(1).get(1);
    360 		key.setComponent(Key.ECC_P, PKCS8.stripLeadingZeros(order.value));
    361
    362 		var coeff_A = domainParameter.get(2).get(0);
    363 		key.setComponent(Key.ECC_A, coeff_A.value);
    364
    365 		var coeff_B = domainParameter.get(2).get(1);
    366 		key.setComponent(Key.ECC_B, coeff_B.value);
    367
    368 		var generatorPoint = domainParameter.get(3).value;
    369
    370 		var coordinates = PKCS8.decodeUncompressedECPoint(generatorPoint);
    371
    372 		key.setComponent(Key.ECC_GX, coordinates.x);
    373 		key.setComponent(Key.ECC_GY, coordinates.y);
    374
    375 		var groupOrder = domainParameter.get(4);
    376
    377 		key.setComponent(Key.ECC_N, PKCS8.stripLeadingZeros(groupOrder.value));
    378 	}
    379
    380 	key.setComponent(Key.ECC_D, encodedKey.get(1).value);
    381
    382 	return key;
    383 }
    384
    385
    386
    387 /**
    388  * Decode a PKCS#1 encoded RSA private key from the given TLV objects and create a GP key object with the private key
    389  *
    390  * @param {ASN1} algparam the algorithm parameter from AlgorithmInfo
    391  * @param {ASN1} privateKey the privateKey element from the PKCS#8 structure
    392  * @return the GP key object
    393  * @type Key
    394  */
    395 PKCS8.decodeRSAPrivateKeyFromPKCS1Format = function(privateKey) {
    396
    397 	var key = new Key();
    398
    399 	key.setType(Key.PRIVATE);
    400
    401 	assert(privateKey.tag == ASN1.SEQUENCE);
    402 	assert(privateKey.isconstructed);
    403 	assert(privateKey.elements >= 9);
    404
    405 	for (var i = 0; i < 9; i++) {
    406 		var e = privateKey.get(i);
    407 		assert(e.tag == ASN1.INTEGER);
    408 		assert(!e.isconstructed);
    409 	}
    410
    411 	assert(privateKey.get(0).value.toUnsigned() == 0);
    412
    413 	var p = PKCS8.stripLeadingZeros(privateKey.get(4).value);
    414 	var l = p.length;
    415 	key.setComponent(Key.CRT_P,   p);
    416 	key.setComponent(Key.CRT_Q,   PKCS8.I2O(privateKey.get(5).value, l));
    417 	key.setComponent(Key.CRT_DP1, PKCS8.I2O(privateKey.get(6).value, l));
    418 	key.setComponent(Key.CRT_DQ1, PKCS8.I2O(privateKey.get(7).value, l));
    419 	key.setComponent(Key.CRT_PQ,  PKCS8.I2O(privateKey.get(8).value, l));
    420
    421 	return key;
    422 }
    423
    424
    425
    426 /**
    427  * Decode a PKCS#1 encoded RSA private key from the given TLV objects and create a GP key object with the public key
    428  *
    429  * @param {ASN1} algparam the algorithm parameter from AlgorithmInfo
    430  * @param {ASN1} privateKey the privateKey element from the PKCS#8 structure
    431  * @return the GP key object
    432  * @type Key
    433  */
    434 PKCS8.decodeRSAPublicKeyFromPKCS1Format = function(privateKey) {
    435
    436 	var key = new Key();
    437
    438 	key.setType(Key.MODULUS);
    439
    440 	assert(privateKey.tag == ASN1.SEQUENCE);
    441 	assert(privateKey.isconstructed);
    442 	assert(privateKey.elements >= 9);
    443
    444 	for (var i = 0; i < 9; i++) {
    445 		var e = privateKey.get(i);
    446 		assert(e.tag == ASN1.INTEGER);
    447 		assert(!e.isconstructed);
    448 	}
    449
    450 	assert(privateKey.get(0).value.toUnsigned() == 0);
    451
    452 	key.setComponent(Key.MODULUS,  PKCS8.stripLeadingZeros(privateKey.get(1).value));
    453 	key.setComponent(Key.EXPONENT, PKCS8.stripLeadingZeros(privateKey.get(2).value));
    454
    455 	return key;
    456 }
    457
    458
    459
    460 /**
    461  * Decode a given PKCS#8 RSA private key from the given TLV objects and create a GP key object
    462  *
    463  * @param {ASN1} algparam the algorithm parameter from AlgorithmInfo
    464  * @param {ASN1} privateKey the privateKey element from the PKCS#8 structure
    465  * @return the GP key object
    466  * @type Key
    467  */
    468 PKCS8.decodeRSAKeyFromPKCS8Format = function(algparam, privateKey) {
    469
    470 	var key = new Key();
    471
    472 	key.setType(Key.PRIVATE);
    473
    474 	assert(algparam.tag == ASN1.NULL);
    475 	assert(!algparam.isconstructed);
    476 	assert(algparam.length == 0);
    477
    478 	return PKCS8.decodeRSAPrivateKeyFromPKCS1Format(privateKey);
    479 }
    480
    481
    482
    483 /**
    484  * Decode a given PKCS#8 private key from the given ByteString and create a GP key object
    485  *
    486  * For now we only support the decoding of ECC private keys in a prime field
    487  *
    488  * @param {ByteString} the private key object in PKCS#8 format
    489  * @return the GP key object
    490  * @type Key
    491  */
    492 PKCS8.decodeKeyFromPKCS8Format = function(encodedKey) {
    493 	var p8 = new ASN1(encodedKey);
    494
    495 	assert(p8.isconstructed);
    496 	assert(p8.elements >= 3);
    497
    498 	var version = p8.get(0);
    499 	assert(version.tag == ASN1.INTEGER);
    500 	assert(version.value.toUnsigned() == 0);
    501
    502 	var pkai = p8.get(1);
    503 	assert(pkai.tag == ASN1.SEQUENCE);
    504 	assert(pkai.isconstructed);
    505 	assert(pkai.elements == 2);
    506 	var keytype = pkai.get(0);
    507
    508 	assert(keytype.tag == ASN1.OBJECT_IDENTIFIER);
    509
    510 	var algparam = pkai.get(1);
    511
    512 	var privateKey = p8.get(2);
    513 	assert(privateKey.tag == ASN1.OCTET_STRING);
    514 	if (privateKey.isconstructed) {
    515 		privateKey = privateKey.get(0);
    516 	} else {
    517 		privateKey = new ASN1(privateKey.value);
    518 	}
    519
    520 	if (keytype.value.equals(PKCS8.rsaEncryption)) {
    521 		return PKCS8.decodeRSAKeyFromPKCS8Format(algparam, privateKey);
    522 	} else if (keytype.value.equals(PKCS8.idEcPublicKey)) {
    523 		return PKCS8.decodeECCKeyFromPKCS8Format(algparam, privateKey);
    524 	} else {
    525 		throw new Error("Unknown key type " + keytype.value.toString(OID));
    526 	}
    527 }
    528
    529
    530
    531 /**
    532  * Simple self-test
    533  */
    534 PKCS8.test = function() {
    535
    536 	// Set OID for EC curve
    537 	var ecCurve = "1.3.36.3.3.2.8.1.1.7";
    538
    539     var crypto = new Crypto("BC");
    540
    541     // Create empty public key object
    542     var pubKey = new Key();
    543     pubKey.setType(Key.PUBLIC);
    544     pubKey.setComponent(Key.ECC_CURVE_OID, new ByteString(ecCurve, OID));
    545
    546     // Create empty private key object
    547     var priKey = new Key();
    548     priKey.setType(Key.PRIVATE);
    549     priKey.setComponent(Key.ECC_CURVE_OID, new ByteString(ecCurve, OID));
    550
    551     // Generate key pair
    552     crypto.generateKeyPair(Crypto.EC, pubKey, priKey);
    553
    554     // Encode
    555     var p8Key = PKCS8.encodeKeyUsingPKCS8Format(priKey);
    556
    557     // Decode
    558     var decodedKeyObject = PKCS8.decodeKeyFromPKCS8Format(p8Key);
    559
    560     // Compare
    561     assert(decodedKeyObject.getComponent(Key.ECC_D).equals(priKey.getComponent(Key.ECC_D)));
    562
    563     assert(decodedKeyObject.getComponent(Key.ECC_GX).equals(priKey.getComponent(Key.ECC_GX)));
    564     assert(decodedKeyObject.getComponent(Key.ECC_GY).equals(priKey.getComponent(Key.ECC_GY)));
    565     assert(decodedKeyObject.getComponent(Key.ECC_A).equals(pubKey.getComponent(Key.ECC_A)));
    566     assert(decodedKeyObject.getComponent(Key.ECC_B).equals(pubKey.getComponent(Key.ECC_B)));
    567
    568     // Encode
    569     var refp8Key = PKCS8.encodeKeyUsingPKCS8Format(decodedKeyObject);
    570
    571     // Compare
    572     assert(p8Key.equals(refp8Key));
    573
    574
    575     // Create empty public key object
    576 	var pubKey = new Key();
    577     pubKey.setType(Key.PUBLIC);
    578     pubKey.setSize(1024);
    579
    580     // Create empty private key object
    581     var priKey = new Key();
    582     priKey.setType(Key.PRIVATE);
    583
    584     // Generate key pair
    585     crypto.generateKeyPair(Crypto.RSA, pubKey, priKey);
    586
    587     // Encode
    588     var p8Key = PKCS8.encodeKeyUsingPKCS8Format(priKey);
    589
    590     // Decode
    591     var decodedKeyObject = PKCS8.decodeKeyFromPKCS8Format(p8Key);
    592
    593     // Compare
    594     assert(decodedKeyObject.getComponent(Key.CRT_P).equals(priKey.getComponent(Key.CRT_P)));
    595     assert(decodedKeyObject.getComponent(Key.CRT_Q).equals(priKey.getComponent(Key.CRT_Q)));
    596     assert(decodedKeyObject.getComponent(Key.CRT_DP1).equals(priKey.getComponent(Key.CRT_DP1)));
    597     assert(decodedKeyObject.getComponent(Key.CRT_DQ1).equals(priKey.getComponent(Key.CRT_DQ1)));
    598     assert(decodedKeyObject.getComponent(Key.CRT_PQ).equals(priKey.getComponent(Key.CRT_PQ)));
    599
    600     // Encode
    601     var refp8Key = PKCS8.encodeKeyUsingPKCS8Format(decodedKeyObject);
    602
    603     // Compare
    604     assert(p8Key.equals(refp8Key));
    605 }
    606