pkcs8.js
Summary
Basic helper functions to convert PKCS#8 data to GP keys and vice versa
function PKCS8() {
}
PKCS8.idEcPublicKey = new ByteString("id-ecPublicKey", OID);
PKCS8.rsaEncryption = new ByteString("1.2.840.113549.1.1.1", OID);
PKCS8.encodeUncompressedECPoint = function(x,y) {
bb = new ByteBuffer();
bb.append(new ByteString("04", HEX));
bb.append(x);
bb.append(y);
return bb.toByteString();
}
PKCS8.decodeUncompressedECPoint = function(uncompressedPoint) {
var length = uncompressedPoint.length - 1;
var sizeOfCoordinate = length >> 1;
var xValue = uncompressedPoint.bytes(1, sizeOfCoordinate);
var yValue = uncompressedPoint.bytes(1 + sizeOfCoordinate, sizeOfCoordinate);
return { x:xValue, y:yValue };
}
PKCS8.I2O = function(value, length) {
if (value.length > length) {
value = value.right(length);
}
while (value.length < length) {
value = PKCS8.PAD.left((length - value.length - 1 & 15) + 1).concat(value);
}
return value;
}
PKCS8.PAD = new ByteString("00000000000000000000000000000000", HEX);
PKCS8.stripLeadingZeros = function(value, size) {
if (typeof(size) == "undefined") {
var limit = value.length;
} else {
limit = value.length - size;
}
var i = 0;
for (; (i < limit) && (value.byteAt(i) == 0); i++);
return value.bytes(i);
}
PKCS8.convertUnsignedInteger = function(value) {
assert(value.length > 0);
var i = 0;
for (; (i < value.length - 1) && (value.byteAt(i) == 0); i++);
if (value.byteAt(i) >= 0x80) {
value = (new ByteString("00", HEX)).concat(value.bytes(i));
} else {
value = value.bytes(i);
}
return value;
}
PKCS8.encodeECCKeyUsingPKCS8Format = function(privateKey) {
var privateKeyInfo = new ASN1(ASN1.SEQUENCE);
privateKeyInfo.add(new ASN1(ASN1.INTEGER, new ByteString("00", HEX)));
var privateKeyAlgorithm = new ASN1(ASN1.SEQUENCE);
privateKeyAlgorithm.add(new ASN1(ASN1.OBJECT_IDENTIFIER, PKCS8.idEcPublicKey));
var domainInfo = new ASN1(ASN1.SEQUENCE);
domainInfo.add(new ASN1(ASN1.INTEGER, PKCS8.stripLeadingZeros(privateKey.getComponent(Key.ECC_H))));
var field = new ASN1(ASN1.SEQUENCE);
field.add(new ASN1(ASN1.OBJECT_IDENTIFIER, new ByteString("prime-field", OID)));
var primeOrder = privateKey.getComponent(Key.ECC_P);
if (primeOrder.byteAt(0) >= 0x80) {
field.add(new ASN1(ASN1.INTEGER, new ByteString("00", HEX).concat(privateKey.getComponent(Key.ECC_P))));
} else {
field.add(new ASN1(ASN1.INTEGER, privateKey.getComponent(Key.ECC_P)));
}
domainInfo.add(field);
var coeff = new ASN1(ASN1.SEQUENCE);
coeff.add(new ASN1(ASN1.OCTET_STRING, privateKey.getComponent(Key.ECC_A)));
coeff.add(new ASN1(ASN1.OCTET_STRING, privateKey.getComponent(Key.ECC_B)));
domainInfo.add(coeff);
var gx = privateKey.getComponent(Key.ECC_GX);
var gy = privateKey.getComponent(Key.ECC_GY);
domainInfo.add(new ASN1(ASN1.OCTET_STRING, PKCS8.encodeUncompressedECPoint(gx, gy)));
var groupOrder = privateKey.getComponent(Key.ECC_N);
if (groupOrder.byteAt(0) >= 0x80) {
domainInfo.add(new ASN1(ASN1.INTEGER, new ByteString("00", HEX).concat(privateKey.getComponent(Key.ECC_N))));
} else {
domainInfo.add(new ASN1(ASN1.INTEGER, privateKey.getComponent(Key.ECC_N)));
}
privateKeyAlgorithm.add(domainInfo);
privateKeyInfo.add(privateKeyAlgorithm);
var encodedPrivateKey = new ASN1(ASN1.OCTET_STRING);
var pk = privateKey.getComponent(Key.ECC_D);
var key = new ASN1(ASN1.SEQUENCE);
key.add(new ASN1(ASN1.INTEGER, new ByteString("01", HEX)));
key.add(new ASN1(ASN1.OCTET_STRING, pk));
encodedPrivateKey.add(key);
privateKeyInfo.add(encodedPrivateKey);
return privateKeyInfo.getBytes();
}
PKCS8.encodeRSAKey = function(privateKey, publicKey) {
var rsaPrivateKey =
new ASN1(ASN1.SEQUENCE);
rsaPrivateKey.add(new ASN1(ASN1.INTEGER, ByteString.valueOf(0)));
if (typeof(publicKey) != "undefined") {
rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(publicKey.getComponent(Key.MODULUS))));
rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(publicKey.getComponent(Key.EXPONENT))));
} else {
rsaPrivateKey.add(new ASN1(ASN1.INTEGER, ByteString.valueOf(0)));
rsaPrivateKey.add(new ASN1(ASN1.INTEGER, ByteString.valueOf(0)));
}
rsaPrivateKey.add(new ASN1(ASN1.INTEGER, ByteString.valueOf(0)));
rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(privateKey.getComponent(Key.CRT_P))));
rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(privateKey.getComponent(Key.CRT_Q))));
rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(privateKey.getComponent(Key.CRT_DP1))));
rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(privateKey.getComponent(Key.CRT_DQ1))));
rsaPrivateKey.add(new ASN1(ASN1.INTEGER, PKCS8.convertUnsignedInteger(privateKey.getComponent(Key.CRT_PQ))));
return rsaPrivateKey.getBytes();
}
PKCS8.encodeRSAKeyUsingPKCS8Format = function(privateKey, publicKey) {
var privateKeyInfo = new ASN1(ASN1.SEQUENCE);
privateKeyInfo.add(new ASN1(ASN1.INTEGER, new ByteString("00", HEX)));
var privateKeyAlgorithm = new ASN1(ASN1.SEQUENCE);
privateKeyAlgorithm.add(new ASN1(ASN1.OBJECT_IDENTIFIER, PKCS8.rsaEncryption));
privateKeyAlgorithm.add(new ASN1(ASN1.NULL));
privateKeyInfo.add(privateKeyAlgorithm);
var encodedPrivateKey = new ASN1(ASN1.OCTET_STRING, PKCS8.encodeRSAKey(privateKey, publicKey));
privateKeyInfo.add(encodedPrivateKey);
return privateKeyInfo.getBytes();
}
PKCS8.encodeKeyUsingPKCS8Format = function(privateKey, publicKey) {
assert(privateKey.getType() == Key.PRIVATE);
if (typeof(privateKey.getComponent(Key.ECC_P)) != "undefined") {
return PKCS8.encodeECCKeyUsingPKCS8Format(privateKey);
} else {
return PKCS8.encodeRSAKeyUsingPKCS8Format(privateKey, publicKey);
}
}
PKCS8.decodeECCKeyFromPKCS8Format = function(domainParameter, encodedKey) {
var key = new Key();
key.setType(Key.PRIVATE);
key.setComponent(Key.ECC_D, encodedKey.get(1).value);
var cofactor = domainParameter.get(0);
key.setComponent(Key.ECC_H, cofactor.value);
var order = domainParameter.get(1).get(1);
key.setComponent(Key.ECC_P, PKCS8.stripLeadingZeros(order.value));
var coeff_A = domainParameter.get(2).get(0);
key.setComponent(Key.ECC_A, coeff_A.value);
var coeff_B = domainParameter.get(2).get(1);
key.setComponent(Key.ECC_B, coeff_B.value);
var generatorPoint = domainParameter.get(3).value;
var coordinates = PKCS8.decodeUncompressedECPoint(generatorPoint);
key.setComponent(Key.ECC_GX, coordinates.x);
key.setComponent(Key.ECC_GY, coordinates.y);
var groupOrder = domainParameter.get(4);
key.setComponent(Key.ECC_N, PKCS8.stripLeadingZeros(groupOrder.value));
return key;
}
PKCS8.decodeRSAKeyFromPKCS8Format = function(algparam, privateKey) {
var key = new Key();
key.setType(Key.PRIVATE);
assert(algparam.tag == ASN1.NULL);
assert(!algparam.isconstructed);
assert(algparam.length == 0);
assert(privateKey.tag == ASN1.SEQUENCE);
assert(privateKey.isconstructed);
assert(privateKey.elements >= 9);
for (var i = 0; i < 9; i++) {
var e = privateKey.get(i);
assert(e.tag == ASN1.INTEGER);
assert(!e.isconstructed);
}
assert(privateKey.get(0).value.toUnsigned() == 0);
var p = PKCS8.stripLeadingZeros(privateKey.get(4).value);
var l = p.length;
key.setComponent(Key.CRT_P, p);
key.setComponent(Key.CRT_Q, PKCS8.I2O(privateKey.get(5).value, l));
key.setComponent(Key.CRT_DP1, PKCS8.I2O(privateKey.get(6).value, l));
key.setComponent(Key.CRT_DQ1, PKCS8.I2O(privateKey.get(7).value, l));
key.setComponent(Key.CRT_PQ, PKCS8.I2O(privateKey.get(8).value, l));
return key;
}
PKCS8.decodeKeyFromPKCS8Format = function(encodedKey) {
var p8 = new ASN1(encodedKey);
assert(p8.isconstructed);
assert(p8.elements >= 3);
var version = p8.get(0);
assert(version.tag == ASN1.INTEGER);
assert(version.value.toUnsigned() == 0);
var pkai = p8.get(1);
assert(pkai.tag == ASN1.SEQUENCE);
assert(pkai.isconstructed);
assert(pkai.elements == 2);
var keytype = pkai.get(0);
assert(keytype.tag == ASN1.OBJECT_IDENTIFIER);
var algparam = pkai.get(1);
var privateKey = p8.get(2);
assert(privateKey.tag == ASN1.OCTET_STRING);
if (privateKey.isconstructed) {
privateKey = privateKey.get(0);
} else {
privateKey = new ASN1(privateKey.value);
}
if (keytype.value.equals(PKCS8.rsaEncryption)) {
return PKCS8.decodeRSAKeyFromPKCS8Format(algparam, privateKey);
} else if (keytype.value.equals(PKCS8.idEcPublicKey)) {
return PKCS8.decodeECCKeyFromPKCS8Format(algparam, privateKey);
} else {
throw new Error("Unknown key type " + keytype.value.toString(OID));
}
}
PKCS8.test = function() {
var ecCurve = "1.3.36.3.3.2.8.1.1.7";
var crypto = new Crypto("BC");
var pubKey = new Key();
pubKey.setType(Key.PUBLIC);
pubKey.setComponent(Key.ECC_CURVE_OID, new ByteString(ecCurve, OID));
var priKey = new Key();
priKey.setType(Key.PRIVATE);
priKey.setComponent(Key.ECC_CURVE_OID, new ByteString(ecCurve, OID));
crypto.generateKeyPair(Crypto.EC, pubKey, priKey);
var p8Key = PKCS8.encodeKeyUsingPKCS8Format(priKey);
var decodedKeyObject = PKCS8.decodeKeyFromPKCS8Format(p8Key);
assert(decodedKeyObject.getComponent(Key.ECC_D).equals(priKey.getComponent(Key.ECC_D)));
assert(decodedKeyObject.getComponent(Key.ECC_GX).equals(priKey.getComponent(Key.ECC_GX)));
assert(decodedKeyObject.getComponent(Key.ECC_GY).equals(priKey.getComponent(Key.ECC_GY)));
assert(decodedKeyObject.getComponent(Key.ECC_A).equals(pubKey.getComponent(Key.ECC_A)));
assert(decodedKeyObject.getComponent(Key.ECC_B).equals(pubKey.getComponent(Key.ECC_B)));
var refp8Key = PKCS8.encodeKeyUsingPKCS8Format(decodedKeyObject);
assert(p8Key.equals(refp8Key));
var pubKey = new Key();
pubKey.setType(Key.PUBLIC);
pubKey.setSize(1024);
var priKey = new Key();
priKey.setType(Key.PRIVATE);
crypto.generateKeyPair(Crypto.RSA, pubKey, priKey);
var p8Key = PKCS8.encodeKeyUsingPKCS8Format(priKey);
var decodedKeyObject = PKCS8.decodeKeyFromPKCS8Format(p8Key);
assert(decodedKeyObject.getComponent(Key.CRT_P).equals(priKey.getComponent(Key.CRT_P)));
assert(decodedKeyObject.getComponent(Key.CRT_Q).equals(priKey.getComponent(Key.CRT_Q)));
assert(decodedKeyObject.getComponent(Key.CRT_DP1).equals(priKey.getComponent(Key.CRT_DP1)));
assert(decodedKeyObject.getComponent(Key.CRT_DQ1).equals(priKey.getComponent(Key.CRT_DQ1)));
assert(decodedKeyObject.getComponent(Key.CRT_PQ).equals(priKey.getComponent(Key.CRT_PQ)));
var refp8Key = PKCS8.encodeKeyUsingPKCS8Format(decodedKeyObject);
assert(p8Key.equals(refp8Key));
}
Documentation generated by
JSDoc on Tue Apr 15 22:10:49 2025