3
  • I am using AWS KMS with ECC_SECG_P256K1 key. When I retreive the public key via aws-sdk the key is 88 bytes, which suppoed to be 64 bytes (as shown in the code)
  • Even more the size of signature is varying between 70,71,72, which means we can't calculate the (r,s) values based on r=[0:32],s=[32,64]
var kms = new AWS.KMS();

var pubKeyParam = {
  KeyId: 'xxxxxxxx', /* required */
};

kms.getPublicKey(pubKeyParam, function(err, data) {
  if (err) console.log(err, err.stack);
  else
      publicKey = data.PublicKey
      console.log(publicKey.length) <-- 88 bytes not 64 bytes 
});

Thanks in advance for help

1 Answers1

3

KMS Public Key Parsing

KMS is returning the public key in ASN.1 format.

If you convert the key using publicKeyFromAsn1 here, it returns 64 bytes:

import * as asn1js from 'asn1js';

function toArrayBuffer(buffer: Buffer): ArrayBuffer {
  const ab = new ArrayBuffer(buffer.length);
  const view = new Uint8Array(ab);
  for (let i = 0; i < buffer.length; ++i) {
    view[i] = buffer[i];
  }
  return ab;
}

// call this with your KMS public key
function publicKeyFromAsn1(buf: Buffer): Buffer {
  const { result } = asn1js.fromBER(toArrayBuffer(buf));
  const values = (result as asn1js.Sequence).valueBlock.value;
  const value = values[1] as asn1js.BitString;
  return Buffer.from(value.valueBlock.valueHex.slice(1));
}

KMS Signature Parsing

The KMS Signature is in DER format (which is valid BER). It ends up looking like this: 30440220{r}0220{s} Here is some parsing logic to help you extract r & s.

import * as asn1js from 'asn1js';

function toArrayBuffer(buffer: Buffer): ArrayBuffer {
  const ab = new ArrayBuffer(buffer.length);
  const view = new Uint8Array(ab);
  for (let i = 0; i < buffer.length; ++i) {
    view[i] = buffer[i];
  }
  return ab;
}

//call this with your signature buffer
function parseBERSignature(sig: Buffer): { r: Buffer; s: Buffer } {
  const { result } = asn1js.fromBER(toArrayBuffer(sig));
  const part1 = (result as asn1js.Sequence).valueBlock.value[0] as asn1js.BitString;
  const part2 = (result as asn1js.Sequence).valueBlock.value[1] as asn1js.BitString;

  return {
    r: Buffer.from(part1.valueBlock.valueHex),
    s: Buffer.from(part2.valueBlock.valueHex),
  };
}