Skip to content

Commit fc5ccfd

Browse files
Convert crypto.ts to use classes
wip convert Node Crypto to class haven't formatted this — will do once contents of class are correct Use of `satisfies` comes from suggestion in [1]. [1] "Allow specifying interface implements clauses for the static side of classes": microsoft/TypeScript#33892 wip convert node crypto CBCCipher to class This concludes the conversion, started in 18ba2a0, of the nodejs platform’s crypto.js file to TypeScript. Convert web’s crypto.ts to use classes TODO need to format, but first document what I did
1 parent 04b3e09 commit fc5ccfd

File tree

2 files changed

+67
-88
lines changed

2 files changed

+67
-88
lines changed

src/platform/nodejs/lib/util/crypto.ts

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Platform from '../../../../common/platform';
44
import crypto from 'crypto';
55
import ErrorInfo from '../../../../common/lib/types/errorinfo';
66
import * as API from '../../../../../ably';
7-
import { IGetCipherParams, CryptoTypes } from '../../../../common/types/ICrypto';
7+
import ICrypto, { IGetCipherParams, CryptoTypes } from '../../../../common/types/ICrypto';
88
import ICipher from '../../../../common/types/ICipher';
99
import { Cipher as NodeCipher, CipherKey as NodeCipherKey } from 'crypto';
1010
import { Bufferlike, Output as BufferUtilsOutput, WordArrayLike } from './bufferutils';
@@ -88,18 +88,6 @@ var Crypto = (function () {
8888
return typeof bufferOrString == 'string' ? Buffer.from(bufferOrString, 'binary') : bufferOrString;
8989
}
9090

91-
interface _CipherParams extends API.Types.CipherParams {
92-
algorithm: string;
93-
keyLength: number;
94-
mode: string;
95-
key: NodeCipherKey;
96-
iv: unknown;
97-
}
98-
99-
interface _CipherParamsConstructor {
100-
new (algorithm: string, keyLength: number, mode: string, key: NodeCipherKey): _CipherParams;
101-
}
102-
10391
/**
10492
* A class encapsulating the client-specifiable parameters for
10593
* the cipher.
@@ -110,8 +98,14 @@ var Crypto = (function () {
11098
* Clients may instance a CipherParams directly and populate it, or may
11199
* query the implementation to obtain a default system CipherParams.
112100
*/
113-
const CipherParams = function (
114-
this: _CipherParams,
101+
class CipherParams implements API.Types.CipherParams {
102+
algorithm: string;
103+
keyLength: number;
104+
mode: string;
105+
key: NodeCipherKey;
106+
iv: unknown;
107+
108+
constructor(
115109
algorithm: string,
116110
keyLength: number,
117111
mode: string,
@@ -122,7 +116,8 @@ var Crypto = (function () {
122116
this.mode = mode;
123117
this.key = key;
124118
this.iv = null;
125-
} as unknown as _CipherParamsConstructor;
119+
}
120+
}
126121

127122
function isInstCipherParams(
128123
params: API.Types.CipherParams | API.Types.CipherParamOptions
@@ -150,9 +145,9 @@ var Crypto = (function () {
150145
* concatenated with the resulting raw ciphertext to construct the "ciphertext"
151146
* data passed to the recipient.
152147
*/
153-
function Crypto() {}
148+
class Crypto {
154149

155-
Crypto.CipherParams = CipherParams;
150+
static CipherParams = CipherParams;
156151

157152
/**
158153
* Obtain a complete CipherParams instance from the provided params, filling
@@ -163,7 +158,7 @@ var Crypto = (function () {
163158
* base64-encoded string. May optionally also contain: algorithm (defaults to
164159
* AES), mode (defaults to 'cbc')
165160
*/
166-
Crypto.getDefaultParams = function (params: API.Types.CipherParamOptions) {
161+
static getDefaultParams(params: API.Types.CipherParamOptions) {
167162
var key: Buffer;
168163

169164
if (!params.key) {
@@ -198,15 +193,15 @@ var Crypto = (function () {
198193

199194
validateCipherParams(cipherParams);
200195
return cipherParams;
201-
};
196+
}
202197

203198
/**
204199
* Generate a random encryption key from the supplied keylength (or the
205200
* default keyLength if none supplied) as a Buffer
206201
* @param keyLength (optional) the required keyLength in bits
207202
* @param callback (optional) (err, key)
208203
*/
209-
Crypto.generateRandomKey = function (keyLength?: number, callback?: API.Types.StandardCallback<API.Types.CipherKey>) {
204+
static generateRandomKey(keyLength?: number, callback?: API.Types.StandardCallback<API.Types.CipherKey>) {
210205
if (arguments.length == 1 && typeof keyLength == 'function') {
211206
callback = keyLength;
212207
keyLength = undefined;
@@ -219,49 +214,43 @@ var Crypto = (function () {
219214
generateRandom((keyLength || DEFAULT_KEYLENGTH) / 8, (err, buf) => {
220215
callback!(err ? ErrorInfo.fromValues(err) : null, buf);
221216
});
222-
};
217+
}
223218

224219
/**
225220
* Internal; get a ChannelCipher instance based on the given cipherParams
226221
* @param params either a CipherParams instance or some subset of its
227222
* fields that includes a key
228223
*/
229-
Crypto.getCipher = function (params: IGetCipherParams<IV>) {
230-
var cipherParams = isInstCipherParams(params) ? (params as _CipherParams) : Crypto.getDefaultParams(params);
224+
static getCipher(params: IGetCipherParams<IV>) {
225+
var cipherParams = isInstCipherParams(params) ? (params as CipherParams) : Crypto.getDefaultParams(params);
231226

232227
var iv = params.iv || generateRandom(DEFAULT_BLOCKLENGTH);
233228
return {
234229
cipherParams: cipherParams,
235230
cipher: new CBCCipher(cipherParams, iv),
236231
};
237-
};
232+
}
238233

239-
interface _CBCCipher extends ICipher<InputPlaintext, OutputCiphertext, InputCiphertext, OutputPlaintext> {
234+
}
235+
236+
Crypto satisfies ICrypto<IV, InputPlaintext, OutputCiphertext, InputCiphertext, OutputPlaintext>;
237+
238+
class CBCCipher implements ICipher<InputPlaintext, OutputCiphertext, InputCiphertext, OutputPlaintext> {
240239
algorithm: string;
241240
key: NodeCipherKey;
242241
iv: Buffer | null;
243242
encryptCipher: NodeCipher;
244243
blockLength: number;
245-
getIv: () => Buffer;
246-
}
247244

248-
interface _CBCCipherConstructor {
249-
new (params: _CipherParams, iv: Buffer): _CBCCipher;
250-
}
251-
252-
const CBCCipher = function CBCCipher(this: _CBCCipher, params: _CipherParams, iv: Buffer) {
245+
constructor(params: CipherParams, iv: Buffer) {
253246
this.algorithm = params.algorithm + '-' + String(params.keyLength) + '-' + params.mode;
254247
this.key = params.key;
255248
this.iv = iv;
256249
this.encryptCipher = crypto.createCipheriv(this.algorithm, this.key, this.iv);
257250
this.blockLength = this.iv.length;
258-
} as unknown as _CBCCipherConstructor;
251+
}
259252

260-
CBCCipher.prototype.encrypt = function (
261-
this: _CBCCipher,
262-
plaintext: InputPlaintext,
263-
callback: (error: Error | null, data: OutputCiphertext | null) => void
264-
) {
253+
encrypt(plaintext: InputPlaintext, callback: (error: Error | null, data: OutputPlaintext | null) => void) {
265254
Logger.logAction(Logger.LOG_MICRO, 'CBCCipher.encrypt()', '');
266255
var plaintextBuffer = Platform.BufferUtils.toBuffer(plaintext);
267256
var plaintextLength = plaintextBuffer.length,
@@ -272,18 +261,18 @@ var Crypto = (function () {
272261
);
273262
var ciphertext = Buffer.concat([iv, toBuffer(cipherOut)]);
274263
return callback(null, ciphertext);
275-
};
264+
}
276265

277-
CBCCipher.prototype.decrypt = function (this: _CBCCipher, ciphertext: InputCiphertext) {
266+
decrypt(ciphertext: InputCiphertext) {
278267
var blockLength = this.blockLength,
279268
decryptCipher = crypto.createDecipheriv(this.algorithm, this.key, ciphertext.slice(0, blockLength)),
280269
plaintext = toBuffer(decryptCipher.update(ciphertext.slice(blockLength))),
281270
final = decryptCipher.final();
282271
if (final && final.length) plaintext = Buffer.concat([plaintext, toBuffer(final)]);
283272
return plaintext;
284-
};
273+
}
285274

286-
CBCCipher.prototype.getIv = function (this: _CBCCipher) {
275+
getIv() {
287276
if (this.iv) {
288277
var iv = this.iv;
289278
this.iv = null;
@@ -295,7 +284,8 @@ var Crypto = (function () {
295284
* sets a new iv (= aes(randomBlock XOR lastCipherText)) as well as
296285
* returning it */
297286
return toBuffer(this.encryptCipher.update(randomBlock));
298-
};
287+
}
288+
}
299289

300290
return Crypto;
301291
})();

src/platform/web/lib/util/crypto.ts

Lines changed: 33 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Platform from '../../../../common/platform';
55
import Logger from '../../../../common/lib/util/logger';
66
import ErrorInfo from 'common/lib/types/errorinfo';
77
import * as API from '../../../../../ably';
8-
import { IGetCipherParams, CryptoTypes } from '../../../../common/types/ICrypto';
8+
import ICrypto, { IGetCipherParams, CryptoTypes } from '../../../../common/types/ICrypto';
99
import ICipher from '../../../../common/types/ICipher';
1010
import { Bufferlike, Output as BufferUtilsOutput } from './bufferutils';
1111

@@ -129,17 +129,6 @@ var Crypto = (function () {
129129
return params instanceof CipherParams;
130130
}
131131

132-
interface _CipherParams extends API.Types.CipherParams {
133-
algorithm: string;
134-
keyLength: number;
135-
mode: string;
136-
key: WordArray;
137-
}
138-
139-
interface _CipherParamsConstructor {
140-
new (algorithm: string, keyLength: number, mode: string, key: WordArray): _CipherParams;
141-
}
142-
143132
/**
144133
* A class encapsulating the client-specifiable parameters for
145134
* the cipher.
@@ -151,8 +140,13 @@ var Crypto = (function () {
151140
* Crypto.getDefaultParams helper, which will fill in any fields not supplied
152141
* with default values and validation the result.
153142
*/
154-
const CipherParams = function (
155-
this: _CipherParams,
143+
class CipherParams implements API.Types.CipherParams {
144+
algorithm: string;
145+
keyLength: number;
146+
mode: string;
147+
key: WordArray;
148+
149+
constructor(
156150
algorithm: string,
157151
keyLength: number,
158152
mode: string,
@@ -162,7 +156,8 @@ var Crypto = (function () {
162156
this.keyLength = keyLength;
163157
this.mode = mode;
164158
this.key = key;
165-
} as unknown as _CipherParamsConstructor;
159+
}
160+
}
166161

167162
/**
168163
* Utility classes and interfaces for message payload encryption.
@@ -182,9 +177,9 @@ var Crypto = (function () {
182177
* concatenated with the resulting raw ciphertext to construct the "ciphertext"
183178
* data passed to the recipient.
184179
*/
185-
function Crypto() {}
180+
class Crypto {
186181

187-
Crypto.CipherParams = CipherParams;
182+
static CipherParams = CipherParams;
188183

189184
/**
190185
* Obtain a complete CipherParams instance from the provided params, filling
@@ -195,7 +190,7 @@ var Crypto = (function () {
195190
* base64-encoded string. May optionally also contain: algorithm (defaults to
196191
* AES), mode (defaults to 'cbc')
197192
*/
198-
Crypto.getDefaultParams = function (params: API.Types.CipherParamOptions) {
193+
static getDefaultParams(params: API.Types.CipherParamOptions) {
199194
var key: WordArray;
200195

201196
if (!params.key) {
@@ -224,15 +219,15 @@ var Crypto = (function () {
224219

225220
validateCipherParams(cipherParams);
226221
return cipherParams;
227-
};
222+
}
228223

229224
/**
230225
* Generate a random encryption key from the supplied keylength (or the
231226
* default keyLength if none supplied) as a CryptoJS WordArray
232227
* @param keyLength (optional) the required keyLength in bits
233228
* @param callback (optional) (err, key)
234229
*/
235-
Crypto.generateRandomKey = function (keyLength?: number, callback?: API.Types.StandardCallback<API.Types.CipherKey>) {
230+
static generateRandomKey(keyLength?: number, callback?: API.Types.StandardCallback<API.Types.CipherKey>) {
236231
if (arguments.length == 1 && typeof keyLength == 'function') {
237232
callback = keyLength;
238233
keyLength = undefined;
@@ -245,38 +240,35 @@ var Crypto = (function () {
245240
generateRandom((keyLength || DEFAULT_KEYLENGTH) / 8, (err, buf) => {
246241
callback!(err ? ErrorInfo.fromValues(err) : null, buf);
247242
});
248-
};
243+
}
249244

250245
/**
251246
* Internal; get a ChannelCipher instance based on the given cipherParams
252247
* @param params either a CipherParams instance or some subset of its
253248
* fields that includes a key
254249
*/
255-
Crypto.getCipher = function (params: IGetCipherParams<IV>) {
256-
var cipherParams = isCipherParams(params) ? (params as _CipherParams) : Crypto.getDefaultParams(params);
250+
static getCipher(params: IGetCipherParams<IV>) {
251+
var cipherParams = isCipherParams(params) ? (params as CipherParams) : Crypto.getDefaultParams(params);
257252
var iv = params.iv != null ? Platform.BufferUtils.toWordArray(params.iv) : null;
258253

259254
return {
260255
cipherParams: cipherParams,
261256
cipher: new CBCCipher(cipherParams, DEFAULT_BLOCKLENGTH_WORDS, iv),
262257
};
263-
};
258+
}
259+
}
264260

265-
interface _CBCCipher extends ICipher<InputPlaintext, OutputCiphertext, InputCiphertext, OutputPlaintext> {
261+
Crypto satisfies ICrypto<IV, InputPlaintext, OutputCiphertext, InputCiphertext, OutputPlaintext>;
262+
263+
class CBCCipher implements ICipher<InputPlaintext, OutputCiphertext, InputCiphertext, OutputPlaintext> {
266264
algorithm: string;
267265
cjsAlgorithm: 'AES';
268266
key: WordArray;
269267
iv: WordArray | null;
270268
blockLengthWords: number;
271-
encryptCipher: ReturnType<typeof CryptoJS.algo.AES.createEncryptor> | null;
272-
getIv: (callback: (error: Error | null, iv: WordArray | null) => void) => void;
273-
}
274-
275-
interface _CBCCipherConstructor {
276-
new (params: _CipherParams, blockLengthWords: number, iv: WordArray | null): _CBCCipher;
277-
}
269+
encryptCipher: ReturnType<typeof CryptoJS.algo.AES.createEncryptor> | null;
278270

279-
const CBCCipher = function (this: _CBCCipher, params: _CipherParams, blockLengthWords: number, iv: WordArray | null) {
271+
constructor(params: CipherParams, blockLengthWords: number, iv: WordArray | null) {
280272
this.algorithm = params.algorithm + '-' + String(params.keyLength) + '-' + params.mode;
281273
const cjsAlgorithm = params.algorithm.toUpperCase().replace(/-\d+$/, '');
282274
if (cjsAlgorithm != 'AES') {
@@ -287,10 +279,9 @@ var Crypto = (function () {
287279
this.iv = iv ? Platform.BufferUtils.toWordArray(iv).clone() : null;
288280
this.blockLengthWords = blockLengthWords;
289281
this.encryptCipher = null;
290-
} as unknown as _CBCCipherConstructor;
282+
}
291283

292-
CBCCipher.prototype.encrypt = function (
293-
this: _CBCCipher,
284+
encrypt(
294285
plaintext: InputPlaintext,
295286
callback: (error: Error | null, data: OutputPlaintext | null) => void
296287
) {
@@ -332,9 +323,9 @@ var Crypto = (function () {
332323
} else {
333324
then();
334325
}
335-
};
326+
}
336327

337-
CBCCipher.prototype.decrypt = function (this: _CBCCipher, ciphertext: InputCiphertext) {
328+
decrypt(ciphertext: InputCiphertext) {
338329
Logger.logAction(Logger.LOG_MICRO, 'CBCCipher.decrypt()', '');
339330
ciphertext = Platform.BufferUtils.toWordArray(ciphertext);
340331
var blockLengthWords = this.blockLengthWords,
@@ -348,12 +339,9 @@ var Crypto = (function () {
348339
decryptCipher.reset();
349340
if (epilogue && epilogue.sigBytes) plaintext.concat(epilogue);
350341
return plaintext;
351-
};
342+
}
352343

353-
CBCCipher.prototype.getIv = function (
354-
this: _CBCCipher,
355-
callback: (error: Error | null, iv: WordArray | null) => void
356-
) {
344+
getIv(callback: (error: Error | null, iv: WordArray | null) => void) {
357345
if (this.iv) {
358346
var iv = this.iv;
359347
this.iv = null;
@@ -372,7 +360,8 @@ var Crypto = (function () {
372360
}
373361
callback(null, self.encryptCipher!.process(randomBlock!));
374362
});
375-
};
363+
}
364+
}
376365

377366
return Crypto;
378367
})();

0 commit comments

Comments
 (0)