Summary
In @xchainjs/xchain-crypto, the keystore encryption derives a 32-byte key via PBKDF2 (dklen = 32) but only the first 16 bytes are used for the cipher, and the cipher is hard-coded to aes-128-ctr. Bumping to aes-256-ctr and feeding the full 32-byte derived key would raise the key-material strength to the modern standard at no extra cost (the bytes are already derived).
Where
packages/xchain-crypto/src/crypto.ts (observed in published lib/index.js, v1.0.7):
const cipher = 'aes-128-ctr' // Encryption cipher
const dklen = 32 // Derived key length
// encrypt
const derivedKey = await pbkdf2Async(Buffer.from(password), salt, kdfParams.c, kdfParams.dklen, hashFunction)
const cipherIV = crypto.createCipheriv(cipher, derivedKey.slice(0, 16), iv) // only first 16 bytes used
// derivedKey.slice(16, 32) is reused as the MAC key
So of the 32 derived bytes, bytes 0..16 are the AES-128 key and bytes 16..32 are the MAC key.
Suggestion
Switch the cipher to aes-256-ctr and use a full 32-byte AES key (deriving a separate MAC key, e.g. by increasing dklen to 64 and splitting 32/32, or deriving the MAC key independently).
Backwards compatibility
This must be done without breaking existing keystores. Decryption already reads the cipher name from keystore.crypto.cipher, so old aes-128-ctr files can still be decrypted as long as the key-slicing for legacy files is preserved. The cleanest path is to bump the keystore version and branch decryption on it: new files use aes-256-ctr + full key, old files keep the current 16-byte slice. Happy to open a PR along these lines if the approach sounds good.
Impact
Low severity — AES-128 has no known practical break — but for software protecting seed phrases, AES-256 is the expected standard and the derived bytes are already available.
Summary
In
@xchainjs/xchain-crypto, the keystore encryption derives a 32-byte key via PBKDF2 (dklen = 32) but only the first 16 bytes are used for the cipher, and the cipher is hard-coded toaes-128-ctr. Bumping toaes-256-ctrand feeding the full 32-byte derived key would raise the key-material strength to the modern standard at no extra cost (the bytes are already derived).Where
packages/xchain-crypto/src/crypto.ts(observed in publishedlib/index.js, v1.0.7):So of the 32 derived bytes, bytes
0..16are the AES-128 key and bytes16..32are the MAC key.Suggestion
Switch the cipher to
aes-256-ctrand use a full 32-byte AES key (deriving a separate MAC key, e.g. by increasingdklento 64 and splitting 32/32, or deriving the MAC key independently).Backwards compatibility
This must be done without breaking existing keystores. Decryption already reads the cipher name from
keystore.crypto.cipher, so oldaes-128-ctrfiles can still be decrypted as long as the key-slicing for legacy files is preserved. The cleanest path is to bump the keystoreversionand branch decryption on it: new files useaes-256-ctr+ full key, old files keep the current 16-byte slice. Happy to open a PR along these lines if the approach sounds good.Impact
Low severity — AES-128 has no known practical break — but for software protecting seed phrases, AES-256 is the expected standard and the derived bytes are already available.