@@ -21,6 +21,7 @@ import * as crypto from 'crypto';
21
21
import * as CryptoJS from 'crypto-js' ;
22
22
23
23
export class Crypto {
24
+ private static AES_ALGO = 'aes-256-gcm' ;
24
25
/**
25
26
* Encrypt data
26
27
* @param {string } data
@@ -93,19 +94,18 @@ export class Crypto {
93
94
}
94
95
// Processing
95
96
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 ( ) ;
102
102
// 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' ) ;
104
104
return result ;
105
105
} ;
106
106
107
107
/**
108
- * Encode a message
108
+ * Encode a message using AES-GCM algorithm
109
109
*
110
110
* @param {string } senderPriv - A sender private key
111
111
* @param {string } recipientPub - A recipient public key
@@ -119,7 +119,7 @@ export class Crypto {
119
119
throw new Error ( 'Missing argument !' ) ;
120
120
}
121
121
// Processing
122
- const iv = Crypto . randomBytes ( 16 ) ;
122
+ const iv = Crypto . randomBytes ( 12 ) ;
123
123
const encoded = Crypto . _encode ( senderPriv , recipientPub , isHexString ? msg : convert . utf8ToHex ( msg ) , iv ) ;
124
124
// Result
125
125
return encoded ;
@@ -131,31 +131,28 @@ export class Crypto {
131
131
* @param {string } recipientPrivate - A recipient private key
132
132
* @param {string } senderPublic - A sender public key
133
133
* @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
135
135
* @return {string } - The decoded payload as hex
136
136
*/
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 => {
138
138
// Error
139
139
if ( ! recipientPrivate || ! senderPublic || ! payload ) {
140
140
throw new Error ( 'Missing argument !' ) ;
141
141
}
142
142
// Processing
143
143
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 ( ) ] ) ;
153
150
// Result
154
- return CryptoJS . enc . Hex . stringify ( plain ) ;
151
+ return decrypted . toString ( 'hex' ) ;
155
152
} ;
156
153
157
154
/**
158
- * Decode an encrypted message payload
155
+ * Decode an encrypted (AES-GCM algorithm) message payload
159
156
*
160
157
* @param {string } recipientPrivate - A recipient private key
161
158
* @param {string } senderPublic - A sender public key
@@ -169,10 +166,15 @@ export class Crypto {
169
166
}
170
167
// Processing
171
168
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
+ }
176
178
} ;
177
179
178
180
/**
0 commit comments