Skip to content

Commit 24df29c

Browse files
committed
- Updated sharedKey derivation using HKDF-HMAC-Sha256
- Updated test vector in unit tests - Fixed unit tests
1 parent a68b9c6 commit 24df29c

File tree

11 files changed

+106
-210
lines changed

11 files changed

+106
-210
lines changed

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,14 @@
5959
"dependencies": {
6060
"bluebird": "^3.5.5",
6161
"catbuffer": "0.0.7",
62-
"nem2-sdk-openapi-typescript-node-client": "0.7.20-beta.6",
6362
"crypto-js": "^3.1.9-1",
63+
"futoin-hkdf": "^1.3.1",
6464
"js-joda": "^1.6.2",
6565
"js-sha256": "^0.9.0",
6666
"js-sha3": "^0.8.0",
6767
"long": "^4.0.0",
6868
"merkletreejs": "^0.1.7",
69+
"nem2-sdk-openapi-typescript-node-client": "0.7.20-beta.6",
6970
"request": "^2.88.0",
7071
"request-promise-native": "^1.0.5",
7172
"ripemd160": "^2.0.2",

src/core/crypto/Crypto.ts

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -228,20 +228,19 @@ export class Crypto {
228228
recipientPub: string,
229229
msg: string,
230230
iv: Uint8Array,
231-
salt: Uint8Array,
232231
signSchema: SignSchema): string => {
233232
// Errors
234-
if (!senderPriv || !recipientPub || !msg || !iv || !salt) { throw new Error('Missing argument !'); }
233+
if (!senderPriv || !recipientPub || !msg || !iv) { throw new Error('Missing argument !'); }
235234
// Processing
236235
const keyPair = KeyPair.createKeyPairFromPrivateKeyString(senderPriv, signSchema);
237236
const pk = convert.hexToUint8(recipientPub);
238-
const encKey = utility.ua2words(KeyPair.deriveSharedKey(keyPair, pk, salt, signSchema), 32);
237+
const encKey = utility.ua2words(KeyPair.deriveSharedKey(keyPair, pk, signSchema), 32);
239238
const encIv = {
240239
iv: utility.ua2words(iv, 16),
241240
};
242241
const encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Hex.parse(msg), encKey, encIv);
243242
// Result
244-
const result = convert.uint8ToHex(salt) + convert.uint8ToHex(iv) + CryptoJS.enc.Hex.stringify(encrypted.ciphertext);
243+
const result = convert.uint8ToHex(iv) + CryptoJS.enc.Hex.stringify(encrypted.ciphertext);
245244
return result;
246245
}
247246

@@ -264,8 +263,7 @@ export class Crypto {
264263
if (!senderPriv || !recipientPub || !msg) { throw new Error('Missing argument !'); }
265264
// Processing
266265
const iv = Crypto.randomBytes(16);
267-
const salt = Crypto.randomBytes(32);
268-
const encoded = Crypto._encode(senderPriv, recipientPub, isHexString ? msg : convert.utf8ToHex(msg), iv, salt, signSchema);
266+
const encoded = Crypto._encode(senderPriv, recipientPub, isHexString ? msg : convert.utf8ToHex(msg), iv, signSchema);
269267
// Result
270268
return encoded;
271269
}
@@ -277,22 +275,20 @@ export class Crypto {
277275
* @param {string} senderPublic - A sender public key
278276
* @param {Uint8Array} payload - An encrypted message payload in bytes
279277
* @param {Uint8Array} iv - 16-byte AES initialization vector
280-
* @param {Uint8Array} salt - 32-byte salt
281278
* @param {SignSchema} signSchema The Sign Schema. (KECCAK(NIS1) / SHA3(Catapult))
282279
* @return {string} - The decoded payload as hex
283280
*/
284281
public static _decode = (recipientPrivate: string,
285282
senderPublic: string,
286283
payload: Uint8Array,
287284
iv: Uint8Array,
288-
salt: Uint8Array,
289285
signSchema: SignSchema): string => {
290286
// Error
291287
if (!recipientPrivate || !senderPublic || !payload) { throw new Error('Missing argument !'); }
292288
// Processing
293289
const keyPair = KeyPair.createKeyPairFromPrivateKeyString(recipientPrivate, signSchema);
294290
const pk = convert.hexToUint8(senderPublic);
295-
const encKey = utility.ua2words(KeyPair.deriveSharedKey(keyPair, pk, salt, signSchema), 32);
291+
const encKey = utility.ua2words(KeyPair.deriveSharedKey(keyPair, pk, signSchema), 32);
296292
const encIv = {
297293
iv: utility.ua2words(iv, 16),
298294
};
@@ -321,10 +317,9 @@ export class Crypto {
321317
if (!recipientPrivate || !senderPublic || !payload) { throw new Error('Missing argument !'); }
322318
// Processing
323319
const binPayload = convert.hexToUint8(payload);
324-
const payloadBuffer = new Uint8Array(binPayload.buffer, 48);
325-
const salt = new Uint8Array(binPayload.buffer, 0, 32);
326-
const iv = new Uint8Array(binPayload.buffer, 32, 16);
327-
const decoded = Crypto._decode(recipientPrivate, senderPublic, payloadBuffer, iv, salt, signSchema);
320+
const payloadBuffer = new Uint8Array(binPayload.buffer, 16);
321+
const iv = new Uint8Array(binPayload.buffer, 0, 16);
322+
const decoded = Crypto._decode(recipientPrivate, senderPublic, payloadBuffer, iv, signSchema);
328323
return decoded.toUpperCase();
329324
}
330325

src/core/crypto/KeyPair.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,10 @@ export class KeyPair {
7070
* @param {SignSchema} signSchema The Sign Schema. (KECCAK(NIS1) / SHA3(Catapult))
7171
* @returns {Uint8Array} The shared key.
7272
*/
73-
public static deriveSharedKey = (keyPair, publicKey: Uint8Array, salt: Uint8Array, signSchema: SignSchema) => {
74-
if (Utility.Key_Size !== salt.length) {
75-
throw Error(`salt has unexpected size: ${salt.length}`);
76-
}
73+
public static deriveSharedKey = (keyPair, publicKey: Uint8Array, signSchema: SignSchema) => {
7774
if (Utility.Key_Size !== publicKey.length) {
78-
throw Error(`public key has unexpected size: ${salt.length}`);
75+
throw Error(`public key has unexpected size: ${publicKey.length}`);
7976
}
80-
return Utility.catapult_crypto.deriveSharedKey(salt, keyPair.privateKey, publicKey, Utility.catapult_hash.func, signSchema);
77+
return Utility.catapult_crypto.deriveSharedKey(keyPair.privateKey, publicKey, Utility.catapult_hash.func, signSchema);
8178
}
8279
}

src/core/crypto/Utilities.ts

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export const Signature_Size = 64;
2424
export const Half_Signature_Size = Signature_Size / 2;
2525
export const Hash_Size = 64;
2626
export const Half_Hash_Size = Hash_Size / 2;
27+
export const hkdf = require('futoin-hkdf');
2728

2829
/**
2930
* Convert an Uint8Array to WordArray
@@ -68,7 +69,7 @@ export const catapult_hash = {
6869
};
6970

7071
// custom catapult crypto functions
71-
export const catapult_crypto = (function() {
72+
export const catapult_crypto = (() => {
7273
function clamp(d) {
7374
d[0] &= 248;
7475
d[31] &= 127;
@@ -82,7 +83,7 @@ export const catapult_crypto = (function() {
8283
return d;
8384
}
8485

85-
const encodedSChecker = (function() {
86+
const encodedSChecker = (() => {
8687
const Is_Reduced = 1;
8788
const Is_Zero = 2;
8889

@@ -202,25 +203,21 @@ export const catapult_crypto = (function() {
202203
return 0 === c.crypto_verify_32(signature, 0, t, 0);
203204
},
204205

205-
deriveSharedKey: (salt, sk, pk, hashfunc, signSchema: SignSchema) => {
206+
deriveSharedKey: (sk, pk, hashfunc, signSchema: SignSchema) => {
206207
const c = nacl;
207208
const d = prepareForScalarMult(sk, hashfunc, signSchema);
208209

209210
// sharedKey = pack(p = d (derived from sk) * q (derived from pk))
210211
const q = [c.gf(), c.gf(), c.gf(), c.gf()];
211212
const p = [c.gf(), c.gf(), c.gf(), c.gf()];
212-
const sharedKey = new Uint8Array(Key_Size);
213+
const sharedSecret = new Uint8Array(Key_Size);
213214
c.unpack(q, pk);
214215
c.scalarmult(p, q, d);
215-
c.pack(sharedKey, p);
216-
// salt the shared key
217-
for (let i = 0; i < Key_Size; ++i) {
218-
sharedKey[i] ^= salt[i];
219-
}
220-
// return the hash of the result
221-
const sharedKeyHash = new Uint8Array(Key_Size);
222-
hashfunc(sharedKeyHash, sharedKey, Key_Size, signSchema);
223-
return sharedKeyHash;
216+
c.pack(sharedSecret, p);
217+
const info = 'catapult';
218+
const hash = 'SHA-256';
219+
const sharedKey = hkdf(sharedSecret, 32, {salt: new Uint8Array(32), info, hash});
220+
return sharedKey;
224221
},
225222
};
226223
})();

src/model/transaction/TransferTransaction.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ export class TransferTransaction extends Transaction {
158158
if (this.message.type === MessageType.PersistentHarvestingDelegationMessage) {
159159
if (this.mosaics.length > 0) {
160160
throw new Error('PersistentDelegationRequestTransaction should be created without Mosaic');
161-
} else if (!/^[0-9a-fA-F]{272}$/.test(this.message.payload)) {
161+
} else if (!/^[0-9a-fA-F]{208}$/.test(this.message.payload)) {
162162
throw new Error('PersistentDelegationRequestTransaction message is invalid');
163163
}
164164
}

0 commit comments

Comments
 (0)