Skip to content

Commit e57dc21

Browse files
Merge pull request #1494 from xchainjs/hippo/fix-xchain-crypto
Fix xchain crypto
2 parents cbc1b10 + 33b3ca5 commit e57dc21

File tree

3 files changed

+55
-3
lines changed

3 files changed

+55
-3
lines changed

.changeset/late-pugs-wash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@xchainjs/xchain-crypto': patch
3+
---
4+
5+
Fix break compatibility

packages/xchain-crypto/__tests__/crypto.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { decryptFromKeystore, encryptToKeyStore, generatePhrase, validatePhrase } from '../src/crypto'
22
import { encodeAddress } from '../src/utils'
3+
import crypto from 'crypto'
34

45
describe('Generate Phrase', () => {
56
it('Generates 12-word phrase', () => {
@@ -14,6 +15,50 @@ describe('Generate Phrase', () => {
1415
})
1516
})
1617

18+
describe('Keystore regression test for encrypt/decrypt with internal migration', () => {
19+
const phrase = 'patient use either flash couple jump castle true broccoli cancel brand mechanic'
20+
const password = '1234'
21+
22+
const expectedKeystore = {
23+
crypto: {
24+
cipher: 'aes-128-ctr',
25+
ciphertext:
26+
'aa6838a2aded226922107d5a2322513e5dd706149831580356dec17d8ab531f873d3f173c2775f125d2b3203c498214039cfa78ac1d0ecb29c3f9be35483c1e4d0e2267bba7b36cec14172f760a91a',
27+
cipherparams: { iv: 'dffdb8bbe92e9a00e173eaa20f1a3784' },
28+
kdf: 'pbkdf2',
29+
kdfparams: {
30+
prf: 'hmac-sha256',
31+
dklen: 32,
32+
salt: 'ead4ad6c09f5a5586235a642fa39c95741b35283304e3fd464d942e300fe0514',
33+
c: 262144,
34+
},
35+
mac: '10597fd811d910c2a9ae3aa4538d03e7ddda672070c1e324603ecf6bcb0426dd',
36+
},
37+
id: '9ad9ea91-22ad-46a7-9613-4f9d190e32ab',
38+
version: 1,
39+
meta: 'xchain-keystore',
40+
}
41+
42+
it('encryptToKeyStore() should produce expected ciphertext and mac', async () => {
43+
jest
44+
.spyOn(crypto, 'randomBytes')
45+
.mockImplementationOnce(() => Buffer.from(expectedKeystore.crypto.kdfparams.salt, 'hex')) // salt
46+
.mockImplementationOnce(() => Buffer.from(expectedKeystore.crypto.cipherparams.iv, 'hex')) // iv
47+
48+
const keystore = await encryptToKeyStore(phrase, password)
49+
50+
expect(keystore.crypto.ciphertext).toBe(expectedKeystore.crypto.ciphertext)
51+
expect(keystore.crypto.mac).toBe(expectedKeystore.crypto.mac)
52+
expect(keystore.crypto.kdfparams).toEqual(expectedKeystore.crypto.kdfparams)
53+
expect(keystore.crypto.cipherparams).toEqual(expectedKeystore.crypto.cipherparams)
54+
})
55+
56+
it('decryptFromKeystore() should return original phrase', async () => {
57+
const result = await decryptFromKeystore(expectedKeystore, password)
58+
expect(result).toBe(phrase)
59+
})
60+
})
61+
1762
describe('Validate Phrase', () => {
1863
it('Validates 12-word Phrase', () => {
1964
const phrase = generatePhrase()

packages/xchain-crypto/src/crypto.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as bip39 from 'bip39'
22
import crypto from 'crypto'
3-
import { blake256 } from '@noble/hashes/blake1.js'
3+
import { blake2b } from '@noble/hashes/blake2'
44
import { v4 as uuidv4 } from 'uuid'
55

66
import { pbkdf2Async } from './utils'
@@ -123,7 +123,9 @@ export const encryptToKeyStore = async (phrase: string, password: string): Promi
123123
const derivedKey = await pbkdf2Async(Buffer.from(password), salt, kdfParams.c, kdfParams.dklen, hashFunction)
124124
const cipherIV = crypto.createCipheriv(cipher, derivedKey.slice(0, 16), iv)
125125
const cipherText = Buffer.concat([cipherIV.update(Buffer.from(phrase, 'utf8')), cipherIV.final()])
126-
const mac_bytes: Uint8Array = blake256(Buffer.concat([derivedKey.slice(16, 32), Buffer.from(cipherText)]))
126+
const mac_bytes: Uint8Array = blake2b(Buffer.concat([derivedKey.slice(16, 32), Buffer.from(cipherText)]), {
127+
dkLen: 32,
128+
})
127129
const mac: string = Buffer.from(mac_bytes).toString('hex')
128130

129131
const cryptoStruct = {
@@ -163,7 +165,7 @@ export const decryptFromKeystore = async (keystore: Keystore, password: string):
163165
)
164166

165167
const ciphertext = Buffer.from(keystore.crypto.ciphertext, 'hex')
166-
const mac_bytes: Uint8Array = blake256(Buffer.concat([derivedKey.slice(16, 32), ciphertext]))
168+
const mac_bytes: Uint8Array = blake2b(Buffer.concat([derivedKey.slice(16, 32), ciphertext]), { dkLen: 32 })
167169
const mac: string = Buffer.from(mac_bytes).toString('hex')
168170

169171
if (mac !== keystore.crypto.mac) throw new Error('Invalid password')

0 commit comments

Comments
 (0)