Skip to content

Commit

Permalink
fix: change hashing, curve and cipher libraries to @noble (#322)
Browse files Browse the repository at this point in the history
* replace stablelib hashes with noble

Signed-off-by: Marin Petrunic <[email protected]>

* update benchmark code

Signed-off-by: Marin Petrunic <[email protected]>

* update noble ciphers

Signed-off-by: Marin Petrunic <[email protected]>

---------

Signed-off-by: Marin Petrunic <[email protected]>
  • Loading branch information
mpetrunic authored Jul 17, 2023
1 parent f03583b commit 5b4f4f2
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 23 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@
"@libp2p/interface-peer-id": "^2.0.0",
"@libp2p/logger": "^2.0.5",
"@libp2p/peer-id": "^2.0.0",
"@stablelib/chacha20poly1305": "^1.0.1",
"@noble/hashes": "^1.3.0",
"@stablelib/x25519": "^1.0.3",
"@noble/curves": "^1.1.0",
"@noble/hashes": "^1.3.1",
"@noble/ciphers": "^0.1.4",
"it-length-prefixed": "^9.0.1",
"it-pair": "^2.0.2",
"it-pb-stream": "^4.0.1",
Expand Down
38 changes: 21 additions & 17 deletions src/crypto/js.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { hkdf } from '@noble/hashes/hkdf'
import { chacha20_poly1305 } from '@noble/ciphers/chacha'
import { x25519 } from '@noble/curves/ed25519'
import { extract, expand } from '@noble/hashes/hkdf'
import { sha256 } from '@noble/hashes/sha256'
import { ChaCha20Poly1305 } from '@stablelib/chacha20poly1305'
import * as x25519 from '@stablelib/x25519'
import type { bytes, bytes32 } from '../@types/basic.js'
import type { Hkdf } from '../@types/handshake.js'
import type { KeyPair } from '../@types/libp2p.js'
Expand All @@ -13,7 +13,9 @@ export const pureJsCrypto: ICryptoInterface = {
},

getHKDF (ck: bytes32, ikm: Uint8Array): Hkdf {
const okm = hkdf(sha256, ikm, ck, undefined, 96)
const prk = extract(sha256, ikm, ck)
const okmU8Array = expand(sha256, prk, undefined, 96)
const okm = okmU8Array

const k1 = okm.subarray(0, 32)
const k2 = okm.subarray(32, 64)
Expand All @@ -23,36 +25,38 @@ export const pureJsCrypto: ICryptoInterface = {
},

generateX25519KeyPair (): KeyPair {
const keypair = x25519.generateKeyPair()
const secretKey = x25519.utils.randomPrivateKey()
const publicKey = x25519.getPublicKey(secretKey)

return {
publicKey: keypair.publicKey,
privateKey: keypair.secretKey
publicKey,
privateKey: secretKey
}
},

generateX25519KeyPairFromSeed (seed: Uint8Array): KeyPair {
const keypair = x25519.generateKeyPairFromSeed(seed)
const publicKey = x25519.getPublicKey(seed)

return {
publicKey: keypair.publicKey,
privateKey: keypair.secretKey
publicKey,
privateKey: seed
}
},

generateX25519SharedKey (privateKey: Uint8Array, publicKey: Uint8Array): Uint8Array {
return x25519.sharedKey(privateKey, publicKey)
return x25519.getSharedSecret(privateKey, publicKey)
},

chaCha20Poly1305Encrypt (plaintext: Uint8Array, nonce: Uint8Array, ad: Uint8Array, k: bytes32): bytes {
const ctx = new ChaCha20Poly1305(k)

return ctx.seal(nonce, plaintext, ad)
return chacha20_poly1305(k, nonce, ad).encrypt(plaintext)
},

chaCha20Poly1305Decrypt (ciphertext: Uint8Array, nonce: Uint8Array, ad: Uint8Array, k: bytes32, dst?: Uint8Array): bytes | null {
const ctx = new ChaCha20Poly1305(k)

return ctx.open(nonce, ciphertext, ad, dst)
const result = chacha20_poly1305(k, nonce, ad).decrypt(ciphertext)
if (dst) {
dst.set(result)
return result
}
return result
}
}
7 changes: 4 additions & 3 deletions src/crypto/streaming.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { TAG_LENGTH } from '@stablelib/chacha20poly1305'
import { NOISE_MSG_MAX_LENGTH_BYTES, NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG } from '../constants.js'
import { uint16BEEncode } from '../encoder.js'
import type { IHandshake } from '../@types/handshake-interface.js'
import type { MetricsRegistry } from '../metrics.js'
import type { Transform } from 'it-stream-types'
import type { Uint8ArrayList } from 'uint8arraylist'

const CHACHA_TAG_LENGTH = 16

// Returns generator that encrypts payload from the user
export function encryptStream (handshake: IHandshake, metrics?: MetricsRegistry): Transform<AsyncIterable<Uint8Array>> {
return async function * (source) {
Expand Down Expand Up @@ -36,15 +37,15 @@ export function decryptStream (handshake: IHandshake, metrics?: MetricsRegistry)
end = chunk.length
}

if (end - TAG_LENGTH < i) {
if (end - CHACHA_TAG_LENGTH < i) {
throw new Error('Invalid chunk')
}
const encrypted = chunk.subarray(i, end)
// memory allocation is not cheap so reuse the encrypted Uint8Array
// see https://github.com/ChainSafe/js-libp2p-noise/pull/242#issue-1422126164
// this is ok because chacha20 reads bytes one by one and don't reread after that
// it's also tested in https://github.com/ChainSafe/as-chacha20poly1305/pull/1/files#diff-25252846b58979dcaf4e41d47b3eadd7e4f335e7fb98da6c049b1f9cd011f381R48
const dst = chunk.subarray(i, end - TAG_LENGTH)
const dst = chunk.subarray(i, end - CHACHA_TAG_LENGTH)
const { plaintext: decrypted, valid } = handshake.decrypt(encrypted, handshake.session, dst)
if (!valid) {
metrics?.decryptErrors.increment()
Expand Down

0 comments on commit 5b4f4f2

Please sign in to comment.