aws-samples / aws-cloudhsm-jce-examples

Sample applications demonstrating how to use the CloudHSM JCE
MIT No Attribution
37 stars 57 forks source link

Is there any EC key import and ECSDA with secpk1 example ? #43

Closed spidemen closed 2 years ago

spidemen commented 3 years ago

I was trying to generate EC key with secpk1, but when I try to sign with this key, the signature I got was not signed by secpk1 curve ???

  public static byte[] sign(byte[] message, PrivateKey key, String signingAlgorithm)
      throws SignatureException, InvalidKeyException, NoSuchAlgorithmException,
      NoSuchProviderException {
    java.security.Signature sig = java.security.Signature.getInstance(signingAlgorithm, "Cavium");
    sig.initSign(key);
    sig.update(message);
    return sig.sign();
  }

there is no any place for us to chose sign curve ??? any example of secpk1 sign ??

rday commented 3 years ago

The curve is chosen during the key generation. In this sample, you can find the curve here:

    // Use the SECP256k1 curve to sign and verify.
    KeyPair kp = new AsymmetricKeys().generateECKeyPair(CaviumECGenParameterSpec.K256, "ectest");

Is there a specific error you are getting while running this sample?

spidemen commented 3 years ago

when I try to use following function with EC private key :

   String keyhex = "a551a5a55ffb2d7225660962b193cbda57b911e2d0fcedaf29d6d7c1f1e71***";
   BigInteger priv = new BigInteger(keyhex, 16);
   String message = "dfdd7f15cb3c2f890d3174c197556ff4ac1b4a981cd2f5e56952f5f71e4d9772";
  public static byte[] sign(byte[] message, PrivateKey key, String signingAlgorithm)
      throws SignatureException, InvalidKeyException, NoSuchAlgorithmException,
      NoSuchProviderException {
    java.security.Signature sig = java.security.Signature.getInstance(signingAlgorithm, "Cavium");
    sig.initSign(key);
    sig.update(message);
    return sig.sign();
  } 

I got following signature:
3045022100f1d1fdd33ef62975024536431899c4202d7c522225274b69724f8ced1755a19d02204b3af8884b25d8756bfefbe9cb31fe96b57f3975d6a8204cf58c412039883b5f.

The same as following code:

      java.security.Signature sig = java.security.Signature.getInstance("ECDSA",
          new BouncyCastleProvider());
      sig.initSign(privateKey);
      sig.update(ByteArray.fromHexString(message));

got signature like 3045022100f1d1fdd33ef62975024536431899c4202d7c522225274b69724f8ced1755a19d02204b3af8884b25d8756bfefbe9cb31fe96b57f3975d6a8204cf58c41203988xxxx

The length is not correct and also it should not start with prefix 30xxxxx. I use another method to do ECSDA and I got following signature, which is correct. 57992f252ccd34cc9213efae413cf70609c3cca1f6afdac90bad5f75709ee5a65dd29db9b3034ce9bf487e28ba119c3ce8f90f9a7bc3da3f330e14861806b55c00
Obviously, the length of second signature is shorter than the first one. My user case is on block chain and I need broadcast this signature and it need to be verified by fullnodes on blockchain.

rday commented 3 years ago

The signatures returned by sign are DER encoded, which is where the 0x30 byte is coming from. It looks like both Cavium and BouncyCastle are returning this format. The signatures look like what I'd expect:

30 45         // DER encoded block of 0x45 bytes
02 21         // integer, 0x21 bytes (r value)
00 f1 d1 fd d3 3e f6 29
75 02 45 36 43 18 99 c4
20 2d 7c 52 22 25 27 4b
69 72 4f 8c ed 17 55 a1
9d 

02 20        // integer, 0x20 bytes (s value)
4b 3a f8 88 4b 25 d8 75
6b fe fb e9 cb 31 fe 96
b5 7f 39 75 d6 a8 20 4c
f5 8c 41 20 39 88 3b 5f

I can't see how you are importing your keyhex value into the hsm. So I can't be sure of that code.

I'm not sure which method you are using to generate your signature. It looks like your signature is 41 bytes, which seems like a valid signature without the DER encoding. You should be able to decode the JCE signature and get a signature which matches your other method.

spidemen commented 3 years ago

Can you show an example of decoding DER 3045022100f1d1fdd33ef62975024536431899c4202d7c522225274b69724f8ced1755a19d02204b3af8884b25d8756bfefbe9cb31fe96b57f3975d6a8204cf58c412039883b5f string ?? like get string like 57992f252ccd34cc9213efae413cf70609c3cca1f6afdac90bad5f75709ee5a65dd29db9b3034ce9bf487e28ba119c3ce8f90f9a7bc3da3f330e14861806b55c00. Can you give some code ?? thanks

spidemen commented 3 years ago
30 45         // DER encoded block of 0x45 bytes
02 21         // integer, 0x21 bytes (r value)
00 f1 d1 fd d3 3e f6 29
75 02 45 36 43 18 99 c4
20 2d 7c 52 22 25 27 4b
69 72 4f 8c ed 17 55 a1
9d 

02 20        // integer, 0x20 bytes (s value)
4b 3a f8 88 4b 25 d8 75
6b fe fb e9 cb 31 fe 96
b5 7f 39 75 d6 a8 20 4c
f5 8c 41 20 39 88 3b 5f

our signature is a combination of r + s + v (r(32 bytes)+s(32 bytes)+v(1 bytes)) , where r and s is 32 bytes and v is only one byte. From above signature string, s value is 0x20bytes (r value) -- 32 bytes , while 0x21 bytes (r value) -- 33 bytes. Any idea about v, the first byte of r value is v ???

rday commented 3 years ago

I'm not sure what v is in your signature, but the confusion may be around the leading 0x00 in the r value. In a DER integer the first bit determines whether the number is signed or not. Since the first byte in this r value is 0xf1 (or any byte that has 1 as the first bit), a leading 0x00 byte must be included to show that this value is an unsigned integer. Stripping that 0x00 byte should be done by your DER decoder (BouncyCastle I assume?). This will leave you with a 32 byte r value and 32 byte s value.

I can't provide code as I'm not sure of your implementation, so my code will certainly be wrong. I would recommend BouncyCastle's ASN1 decoder, because I think you are already using BouncyCastle? This will expose the DERIntegers, which could then be concatenated to get your preferred format.

rday commented 2 years ago

Closing after inactivity, please re-open if you are still experiencing problems.