christophhagen / CryptoKit25519

A Swift module for Curve25519 functions and AES-GCM encryption (compatible with Apple CryptoKit)
MIT License
7 stars 3 forks source link

Cannot recover the correct public key from private keys #1

Open samueltangz opened 4 years ago

samueltangz commented 4 years ago

Hi, I have been testing around with this library and found that the public key could not be correctly computed from the private keys.

import CryptoKit25519

let k1 = try! Curve25519.KeyAgreement.PrivateKey(rawRepresentation: Data([
  75, 157, 102, 134, 12, 57, 222, 49, 73, 43, 219, 59, 9, 5, 39, 191,
  102, 239, 30, 167, 95, 16, 91, 182, 248, 115, 40, 223, 187, 159, 227, 55]))
print("actual  ", Array(k1.publicKey.rawRepresentation))
print("expected", [30, 222, 35, 48, 128, 169, 48, 95, 101, 138, 236, 237, 7, 239, 4, 206, 211, 112, 181, 241, 187, 160, 153, 179, 171, 195, 158, 199, 180, 245, 168, 63])
// actual   [24, 233, 101, 77, 124, 166, 123, 38, 231, 73, 205, 242, 13, 207, 115, 34, 178, 98, 195, 39, 109, 223, 183, 78, 35, 64, 1, 165, 74, 213, 89, 46]
// expected [30, 222, 35, 48, 128, 169, 48, 95, 101, 138, 236, 237, 7, 239, 4, 206, 211, 112, 181, 241, 187, 160, 153, 179, 171, 195, 158, 199, 180, 245, 168, 63]

let k2 = try! Curve25519.KeyAgreement.PrivateKey(rawRepresentation: Data([
  0xc8, 0x06, 0x43, 0x9d, 0xc9, 0xd2, 0xc4, 0x76, 0xff, 0xed, 0x8f, 0x25, 0x80, 0xc0, 0x88, 0x8d,
  0x58, 0xab, 0x40, 0x6b, 0xf7, 0xae, 0x36, 0x98, 0x87, 0x90, 0x21, 0xb9, 0x6b, 0xb4, 0xbf, 0x59]))
print("actual  ", Array(k2.publicKey.rawRepresentation))
print("expected", [
  0x1b, 0xb7, 0x59, 0x66, 0xf2, 0xe9, 0x3a, 0x36, 0x91, 0xdf, 0xff, 0x94, 0x2b, 0xb2, 0xa4, 0x66,
  0xa1, 0xc0, 0x8b, 0x8d, 0x78, 0xca, 0x3f, 0x4d, 0x6d, 0xf8, 0xb8, 0xbf, 0xa2, 0xe4, 0xee, 0x28])
// actual   [27, 183, 89, 102, 242, 233, 58, 54, 145, 223, 255, 148, 43, 178, 164, 102, 161, 192, 139, 141, 120, 202, 63, 77, 109, 248, 184, 191, 162, 228, 238, 40]
// expected [27, 183, 89, 102, 242, 233, 58, 54, 145, 223, 255, 148, 43, 178, 164, 102, 161, 192, 139, 141, 120, 202, 63, 77, 109, 248, 184, 191, 162, 228, 238, 40]

The two test vectors are, respectively, extracted from test vector from Noise protocol, and the test case given in Curve25519 package.

(First test vector)
Private key: 4b9d66860c39de31492bdb3b090527bf66ef1ea75f105bb6f87328dfbb9fe337
Public key:  1ede233080a9305f658aeced07ef04ced370b5f1bba099b3abc39ec7b4f5a83f

The cause is, some of the bits in the secret key must be unset (and some otherwise need to be set) before computation:

func normalize(secretKey: [UInt8]) -> [UInt8] {
  var newSecretKey = secretKey
  newSecretKey[0] &= 0xf8
  newSecretKey[31] &= 0x3f
  newSecretKey[31] |= 0x40
  return newSecretKey
}
christophhagen commented 4 years ago

Hi,

thanks for raising this issue.

I resolved the issue by correctly normalizing the key bytes before calculating the public key. Additional fixes now ensure compatibility for signing keys as well.

The newest release 0.6 also fixes some more compatibility issues. Additional tests compare the functionality with Apple CryptoKit.

I hope the library now performs as expected.