@@ -21,6 +21,7 @@ import * as crypto from 'crypto';
2121import * as CryptoJS from 'crypto-js' ;
2222
2323export class Crypto {
24+ private static AES_ALGO = 'aes-256-gcm' ;
2425 /**
2526 * Encrypt data
2627 * @param {string } data
@@ -93,19 +94,18 @@ export class Crypto {
9394 }
9495 // Processing
9596 const keyPair = KeyPair . createKeyPairFromPrivateKeyString ( senderPriv ) ;
96- const pk = convert . hexToUint8 ( recipientPub ) ;
97- const encKey = utility . ua2words ( utility . catapult_crypto . deriveSharedKey ( keyPair . privateKey , pk ) , 32 ) ;
98- const encIv = {
99- iv : utility . ua2words ( iv , 16 ) ,
100- } ;
101- const encrypted = CryptoJS . AES . encrypt ( CryptoJS . enc . Hex . parse ( msg ) , encKey , encIv ) ;
97+ const encKey = Buffer . from ( utility . catapult_crypto . deriveSharedKey ( keyPair . privateKey , convert . hexToUint8 ( recipientPub ) ) , 32 ) ;
98+ const encIv = Buffer . from ( iv ) ;
99+ const cipher = crypto . createCipheriv ( Crypto . AES_ALGO , encKey , encIv ) ;
100+ const encrypted = Buffer . concat ( [ cipher . update ( Buffer . from ( convert . hexToUint8 ( msg ) ) ) , cipher . final ( ) ] ) ;
101+ const tag = cipher . getAuthTag ( ) ;
102102 // Result
103- const result = convert . uint8ToHex ( iv ) + CryptoJS . enc . Hex . stringify ( encrypted . ciphertext ) ;
103+ const result = tag . toString ( 'hex' ) + encIv . toString ( 'hex' ) + encrypted . toString ( 'hex' ) ;
104104 return result ;
105105 } ;
106106
107107 /**
108- * Encode a message
108+ * Encode a message using AES-GCM algorithm
109109 *
110110 * @param {string } senderPriv - A sender private key
111111 * @param {string } recipientPub - A recipient public key
@@ -119,7 +119,7 @@ export class Crypto {
119119 throw new Error ( 'Missing argument !' ) ;
120120 }
121121 // Processing
122- const iv = Crypto . randomBytes ( 16 ) ;
122+ const iv = Crypto . randomBytes ( 12 ) ;
123123 const encoded = Crypto . _encode ( senderPriv , recipientPub , isHexString ? msg : convert . utf8ToHex ( msg ) , iv ) ;
124124 // Result
125125 return encoded ;
@@ -131,31 +131,28 @@ export class Crypto {
131131 * @param {string } recipientPrivate - A recipient private key
132132 * @param {string } senderPublic - A sender public key
133133 * @param {Uint8Array } payload - An encrypted message payload in bytes
134- * @param {Uint8Array } iv - 16-byte AES initialization vector
134+ * @param {Uint8Array } tagAndIv - 16-bytes AES auth tag and 12 -byte AES initialization vector
135135 * @return {string } - The decoded payload as hex
136136 */
137- public static _decode = ( recipientPrivate : string , senderPublic : string , payload : Uint8Array , iv : Uint8Array ) : string => {
137+ public static _decode = ( recipientPrivate : string , senderPublic : string , payload : Uint8Array , tagAndIv : Uint8Array ) : string => {
138138 // Error
139139 if ( ! recipientPrivate || ! senderPublic || ! payload ) {
140140 throw new Error ( 'Missing argument !' ) ;
141141 }
142142 // Processing
143143 const keyPair = KeyPair . createKeyPairFromPrivateKeyString ( recipientPrivate ) ;
144- const pk = convert . hexToUint8 ( senderPublic ) ;
145- const encKey = utility . ua2words ( utility . catapult_crypto . deriveSharedKey ( keyPair . privateKey , pk ) , 32 ) ;
146- const encIv = {
147- iv : utility . ua2words ( iv , 16 ) ,
148- } ;
149- const encrypted = {
150- ciphertext : utility . ua2words ( payload , payload . length ) ,
151- } ;
152- const plain = CryptoJS . AES . decrypt ( encrypted , encKey , encIv ) ;
144+ const encKey = Buffer . from ( utility . catapult_crypto . deriveSharedKey ( keyPair . privateKey , convert . hexToUint8 ( senderPublic ) ) , 32 ) ;
145+ const encIv = Buffer . from ( new Uint8Array ( tagAndIv . buffer , 16 , 12 ) ) ;
146+ const encTag = Buffer . from ( new Uint8Array ( tagAndIv . buffer , 0 , 16 ) ) ;
147+ const cipher = crypto . createDecipheriv ( Crypto . AES_ALGO , encKey , encIv ) ;
148+ cipher . setAuthTag ( encTag ) ;
149+ const decrypted = Buffer . concat ( [ cipher . update ( Buffer . from ( payload ) ) , cipher . final ( ) ] ) ;
153150 // Result
154- return CryptoJS . enc . Hex . stringify ( plain ) ;
151+ return decrypted . toString ( 'hex' ) ;
155152 } ;
156153
157154 /**
158- * Decode an encrypted message payload
155+ * Decode an encrypted (AES-GCM algorithm) message payload
159156 *
160157 * @param {string } recipientPrivate - A recipient private key
161158 * @param {string } senderPublic - A sender public key
@@ -169,10 +166,15 @@ export class Crypto {
169166 }
170167 // Processing
171168 const binPayload = convert . hexToUint8 ( payload ) ;
172- const payloadBuffer = new Uint8Array ( binPayload . buffer , 16 ) ;
173- const iv = new Uint8Array ( binPayload . buffer , 0 , 16 ) ;
174- const decoded = Crypto . _decode ( recipientPrivate , senderPublic , payloadBuffer , iv ) ;
175- return decoded . toUpperCase ( ) ;
169+ const payloadBuffer = new Uint8Array ( binPayload . buffer , 16 + 12 ) ; //tag + iv
170+ const tagAndIv = new Uint8Array ( binPayload . buffer , 0 , 16 + 12 ) ;
171+ try {
172+ const decoded = Crypto . _decode ( recipientPrivate , senderPublic , payloadBuffer , tagAndIv ) ;
173+ return decoded . toUpperCase ( ) ;
174+ } catch {
175+ // To return empty string rather than error throwing if authentication failed
176+ return '' ;
177+ }
176178 } ;
177179
178180 /**
0 commit comments