Skip to content

Commit

Permalink
fix: ???
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasbrugneaux committed Jan 18, 2024
1 parent cedd9f4 commit 0e116b8
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 19 deletions.
4 changes: 2 additions & 2 deletions packages/sdk/cryptographic-utils/src/dataEncryptionKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Bip39, generateKeys } from './account'
* @returns {string} Corresponding compressed public key in hex encoding with '0x' leader.
*/
export function compressedPubKey(privateKey: Buffer): string {
return ensureLeading0x(bytesToHex(secp256k1.getPublicKey(privateKey)))
return ensureLeading0x(bytesToHex(secp256k1.getPublicKey(privateKey))).slice(1)
}

/**
Expand All @@ -21,7 +21,7 @@ export function compressedPubKey(privateKey: Buffer): string {
* @returns Decompresssed public key without prefix.
*/
export function decompressPublicKey(publicKey: Buffer): Buffer {
return Buffer.from(secp256k1.getSharedSecret(BigInt(1), publicKey, false))
return Buffer.from(secp256k1.getSharedSecret(BigInt(1), publicKey, false)).slice(1)
}

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/sdk/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@
"@types/node": "^18.7.16",
"bignumber.js": "^9.0.0",
"bn.js": "4.11.9",
"elliptic": "^6.5.4",
"ethereum-cryptography": "1.2.0",
"fp-ts": "2.1.1",
"io-ts": "2.0.1",
"rlp": "^2.2.4",
"web3-eth-abi": "1.10.0",
"web3-utils": "1.10.0",
"elliptic": "^6.5.4"
"web3-utils": "1.10.0"
},
"devDependencies": {
"@celo/typescript": "0.0.1"
Expand Down
21 changes: 13 additions & 8 deletions packages/sdk/utils/src/ecies.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { bytesToUtf8, utf8ToBytes } from '@noble/ciphers/utils'
import { bytesToUtf8, u8, utf8ToBytes } from '@noble/ciphers/utils'
import { randomBytes } from '@noble/ciphers/webcrypto/utils'
import { secp256k1 } from '@noble/curves/secp256k1'
import { ECIES } from './ecies'
Expand All @@ -20,15 +20,20 @@ describe('ECIES', () => {
})

it('should not regress', () => {
const snapshotPrivKey = Buffer.from(
'f353837781491b9ded31b6cb669c867e4c91f0ccfdaa85db4b1f0a814bc060c5',
'hex'
// snapshot generated on master at commit=4861e71d0
// with message='foo'
// and privkey='0xd2a515a64d37407f0e0e4a6a6a69a95eeb5ef8c2524ef01a6ffc6e3b39e0661b'
const snapshotPrivKey = u8(
Buffer.from('f353837781491b9ded31b6cb669c867e4c91f0ccfdaa85db4b1f0a814bc060c5', 'hex')
)
const pubKey = privateToPublic(snapshotPrivKey)
const message = Buffer.from('foo')
expect(ECIES.Encrypt(pubKey, message).toString('hex')).toMatchInlineSnapshot(
`"04f8a3e50423af34892f3a64bfa37b8c68bf4b378a5029964c563d17ab66a99bc75a101b30b95e64267219305eb5c8f65fd3b1081cfa7f549638a430d0712a58669b90d413329c70d1159664e73e1477a8a4151de90f94abeafe52cfbfb37e414df35f16a172b7d1c6b1a14d6559b7657e446f9e"`
const snapshotEncrypted = Buffer.from(
'04f8a3e50423af34892f3a64bfa37b8c68bf4b378a5029964c563d17ab66a99bc75a101b30b95e64267219305eb5c8f65fd3b1081cfa7f549638a430d0712a58669b90d413329c70d1159664e73e1477a8a4151de90f94abeafe52cfbfb37e414df35f16a172b7d1c6b1a14d6559b7657e446f9e',
'hex'
)
// secp256k1.getPublicKey(snapshotPrivKey).slice(1)

// const _message = Buffer.from('foo')
expect(ECIES.Decrypt(snapshotPrivKey, snapshotEncrypted).toString()).toEqual('foo')
})
})

Expand Down
59 changes: 52 additions & 7 deletions packages/sdk/utils/src/ecies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,49 @@ import { randomBytes } from '@noble/hashes/utils'

export const IV_LENGTH = 16

/**
* Increments big endian uint32
*
* @param {Buffer} ctr 32 bit unsigned big endian integer to increment.
* @returns Incremented counter.
*/
const IncCounter = (ctr: Buffer) => {
for (let i = ctr.length - 1; i >= 0; i--) {
ctr[i]++
if (ctr[i] !== 0) {
return ctr
}
}
return ctr
}

/**
* NIST 8000-56C Rev 1 One Step KDF with the following parameters:
* - H(x) is SHA-256(x)
* - Fixed info is null
*
* TODO:
* - Implement proper ceiling on reps.
*
* @param {Buffer} px Input keying material to derive key from.
* @param {number} kdLen Length of output in bytes
* @returns {Buffer} Output keying material of length kdLen bytes.
*/
export const ConcatKDF = (px: Buffer, kdLen: number) => {
const blockSize = 32
const reps = ((kdLen + 7) * 8) / (blockSize * 8)
let counter = Buffer.from('00000001', 'hex')
let k = Buffer.from('00', 'hex')
for (let i = 0; i <= reps; i++) {
const hash = sha256.create()
hash.update(counter)
hash.update(px)
k = Buffer.concat([k, hash.digest()])
counter = IncCounter(counter)
}
return k.slice(1, kdLen + 1)
}

/**
* AES-128 CTR encrypt
* @param {Uint8Array} encryptionKey
Expand Down Expand Up @@ -92,7 +135,7 @@ export function AES128DecryptAndHMAC(
return AES128Decrypt(encryptionKey, iv, message)
}

const COMPRESSED_KEY_LENGTH = secp256k1.CURVE.Fp.BYTES + 1 // e.g. 33 for 32
const UNCOMPRESSED_KEY_LENGTH = 65
/**
* ECIES encrypt
* @param {Buffer} pubKeyTo Ethereum pub key, 64 bytes.
Expand All @@ -101,21 +144,22 @@ const COMPRESSED_KEY_LENGTH = secp256k1.CURVE.Fp.BYTES + 1 // e.g. 33 for 32
*/
export function Encrypt(pubKeyTo: PubKey, plaintext: Uint8Array) {
const ephemPrivKey = secp256k1.utils.randomPrivateKey()
const ephemPubKey = Buffer.from(secp256k1.getPublicKey(ephemPrivKey))
const ephemPubKey = Buffer.from(secp256k1.getPublicKey(ephemPrivKey, false))
const ephemPubKeyEncoded = Buffer.from(ephemPubKey)
if (typeof pubKeyTo === 'string') {
pubKeyTo = secp256k1.ProjectivePoint.fromHex(pubKeyTo).toRawBytes()
}

const pubKeyToEncoded = Buffer.concat([Buffer.from([0x04]), pubKeyTo as Buffer])
const px = secp256k1.getSharedSecret(ephemPrivKey, pubKeyToEncoded).slice(1)
const px = secp256k1.getSharedSecret(ephemPrivKey, pubKeyToEncoded, false).slice(1)

const hash = hkdf(sha256, px, undefined, undefined, 32)
// const hash = ConcatKDF(Buffer.from(px), 32)
const encryptionKey = hash.subarray(0, 16)
const macKey = sha256.create().update(hash.subarray(16)).digest()
const message = AES128EncryptAndHMAC(Buffer.from(encryptionKey), macKey, plaintext)
const serializedCiphertext = Buffer.concat([
ephemPubKeyEncoded, // {COMPRESSED_KEY_LENGTH} bytes
ephemPubKeyEncoded, // {UNCOMPRESSED_KEY_LENGTH} bytes
message, // iv + ciphertext + mac (min 48 bytes)
])

Expand All @@ -130,11 +174,12 @@ export function Encrypt(pubKeyTo: PubKey, plaintext: Uint8Array) {
*/
export function Decrypt(privKey: PrivKey, encrypted: Buffer) {
// Read iv, ephemPubKey, mac, ciphertext from encrypted message
const ephemPubKeyEncoded = u8(encrypted).slice(0, COMPRESSED_KEY_LENGTH)
const symmetricEncrypted = u8(encrypted).slice(COMPRESSED_KEY_LENGTH)
const ephemPubKeyEncoded = u8(encrypted).slice(0, UNCOMPRESSED_KEY_LENGTH)
const symmetricEncrypted = u8(encrypted).slice(UNCOMPRESSED_KEY_LENGTH)

const px = secp256k1.getSharedSecret(privKey, ephemPubKeyEncoded).slice(1)
const px = secp256k1.getSharedSecret(privKey, ephemPubKeyEncoded, false).slice(1)
const hash = hkdf(sha256, px, undefined, undefined, 32)
// const hash = ConcatKDF(Buffer.from(px), 32)
// km, ke
const encryptionKey = hash.subarray(0, 16)

Expand Down
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1893,6 +1893,7 @@ __metadata:
"@types/node": "npm:^18.7.16"
bignumber.js: "npm:^9.0.0"
bn.js: "npm:4.11.9"
elliptic: "npm:^6.5.4"
ethereum-cryptography: "npm:1.2.0"
fp-ts: "npm:2.1.1"
io-ts: "npm:2.0.1"
Expand Down

0 comments on commit 0e116b8

Please sign in to comment.