Skip to content

Commit

Permalink
fix: replace salt with info
Browse files Browse the repository at this point in the history
  • Loading branch information
neekolas authored and rygine committed Mar 12, 2024
1 parent 47d63da commit a0e3ecd
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 17 deletions.
9 changes: 5 additions & 4 deletions src/crypto/encryption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Ciphertext, { AESGCMNonceSize, KDFSaltSize } from './Ciphertext'
import crypto from './crypto'

const hkdfNoInfo = new Uint8Array().buffer
const hkdfNoSalt = new Uint8Array().buffer

// This is a variation of https://github.com/paulmillr/noble-secp256k1/blob/main/index.ts#L1378-L1388
// that uses `digest('SHA-256', bytes)` instead of `digest('SHA-256', bytes.buffer)`
Expand Down Expand Up @@ -86,13 +87,13 @@ async function hkdf(secret: Uint8Array, salt: Uint8Array): Promise<CryptoKey> {

export async function hkdfHmacKey(
secret: Uint8Array,
salt: Uint8Array
info: Uint8Array
): Promise<CryptoKey> {
const key = await crypto.subtle.importKey('raw', secret, 'HKDF', false, [
'deriveKey',
])
return crypto.subtle.deriveKey(
{ name: 'HKDF', hash: 'SHA-256', salt, info: hkdfNoInfo },
{ name: 'HKDF', hash: 'SHA-256', salt: hkdfNoSalt, info },
key,
{ name: 'HMAC', hash: 'SHA-256', length: 256 },
true,
Expand All @@ -102,10 +103,10 @@ export async function hkdfHmacKey(

export async function generateHmacSignature(
secret: Uint8Array,
salt: Uint8Array,
info: Uint8Array,
message: Uint8Array
): Promise<Uint8Array> {
const key = await hkdfHmacKey(secret, salt)
const key = await hkdfHmacKey(secret, info)
const signed = await crypto.subtle.sign('HMAC', key, message)
return new Uint8Array(signed)
}
Expand Down
4 changes: 2 additions & 2 deletions src/keystore/InMemoryKeystore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,10 +305,10 @@ export default class InMemoryKeystore implements KeystoreInterface {
const thirtyDayPeriodsSinceEpoch = Math.floor(
Date.now() / 1000 / 60 / 60 / 24 / 30
)
const salt = `${thirtyDayPeriodsSinceEpoch}-${this.accountAddress}`
const info = `${thirtyDayPeriodsSinceEpoch}-${this.accountAddress}`
const hmac = await generateHmacSignature(
keyMaterial,
new TextEncoder().encode(salt),
new TextEncoder().encode(info),
headerBytes
)

Expand Down
32 changes: 21 additions & 11 deletions test/crypto/encryption.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,42 @@ import crypto from '../../src/crypto/crypto'
describe('HMAC encryption', () => {
it('generates and validates HMAC', async () => {
const secret = crypto.getRandomValues(new Uint8Array(32))
const salt = crypto.getRandomValues(new Uint8Array(32))
const info = crypto.getRandomValues(new Uint8Array(32))
const message = crypto.getRandomValues(new Uint8Array(32))
const hmac = await generateHmacSignature(secret, salt, message)
const key = await hkdfHmacKey(secret, salt)
const hmac = await generateHmacSignature(secret, info, message)
const key = await hkdfHmacKey(secret, info)
const valid = await verifyHmacSignature(key, hmac, message)
expect(valid).toBe(true)
})

it('generates and validates HMAC with imported key', async () => {
const secret = crypto.getRandomValues(new Uint8Array(32))
const salt = crypto.getRandomValues(new Uint8Array(32))
const info = crypto.getRandomValues(new Uint8Array(32))
const message = crypto.getRandomValues(new Uint8Array(32))
const hmac = await generateHmacSignature(secret, salt, message)
const key = await hkdfHmacKey(secret, salt)
const hmac = await generateHmacSignature(secret, info, message)
const key = await hkdfHmacKey(secret, info)
const exportedKey = await exportHmacKey(key)
const importedKey = await importHmacKey(exportedKey)
const valid = await verifyHmacSignature(importedKey, hmac, message)
expect(valid).toBe(true)
})

it('generates different HMAC keys with different infos', async () => {
const secret = crypto.getRandomValues(new Uint8Array(32))
const info1 = crypto.getRandomValues(new Uint8Array(32))
const info2 = crypto.getRandomValues(new Uint8Array(32))
const key1 = await hkdfHmacKey(secret, info1)
const key2 = await hkdfHmacKey(secret, info2)

expect(await exportHmacKey(key1)).not.toEqual(await exportHmacKey(key2))
})

it('fails to validate HMAC with wrong message', async () => {
const secret = crypto.getRandomValues(new Uint8Array(32))
const salt = crypto.getRandomValues(new Uint8Array(32))
const info = crypto.getRandomValues(new Uint8Array(32))
const message = crypto.getRandomValues(new Uint8Array(32))
const hmac = await generateHmacSignature(secret, salt, message)
const key = await hkdfHmacKey(secret, salt)
const hmac = await generateHmacSignature(secret, info, message)
const key = await hkdfHmacKey(secret, info)
const valid = await verifyHmacSignature(
key,
hmac,
Expand All @@ -46,9 +56,9 @@ describe('HMAC encryption', () => {

it('fails to validate HMAC with wrong key', async () => {
const secret = crypto.getRandomValues(new Uint8Array(32))
const salt = crypto.getRandomValues(new Uint8Array(32))
const info = crypto.getRandomValues(new Uint8Array(32))
const message = crypto.getRandomValues(new Uint8Array(32))
const hmac = await generateHmacSignature(secret, salt, message)
const hmac = await generateHmacSignature(secret, info, message)
const valid = await verifyHmacSignature(
await hkdfHmacKey(
crypto.getRandomValues(new Uint8Array(32)),
Expand Down

0 comments on commit a0e3ecd

Please sign in to comment.