Skip to content

Commit 76a56ad

Browse files
authoredNov 15, 2022
fix: CDK does not work in FIPS-restricted environments (#22878)
In an environment where node is compiled with FIPS restrictions in mind, `crypto.createHash('md5')` does not work, for fear of MD5 being used for crypto purposes. We do not use it for crypto purposes, just to come up with unique identifiers for certain constructs. Nevertheless, CDK cannot work if `md5` is not available from the Node standard library. Fall back to a pure JavaScript implementation if the built-in MD5 hash does not work. This results in about a ~10x performance penalty, but the only thing we can do in order to produce the same templates. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent e4fdb02 commit 76a56ad

File tree

18 files changed

+287
-53
lines changed

18 files changed

+287
-53
lines changed
 

‎packages/@aws-cdk/aws-apigateway/lib/deployment.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import * as crypto from 'crypto';
21
import { Lazy, RemovalPolicy, Resource, CfnResource } from '@aws-cdk/core';
2+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
33
import { Construct } from 'constructs';
44
import { CfnDeployment } from './apigateway.generated';
55
import { Method } from './method';
@@ -173,9 +173,7 @@ class LatestDeploymentResource extends CfnDeployment {
173173
// if hash components were added to the deployment, we use them to calculate
174174
// a logical ID for the deployment resource.
175175
if (hash.length > 0) {
176-
const md5 = crypto.createHash('md5');
177-
hash.map(x => this.stack.resolve(x)).forEach(c => md5.update(JSON.stringify(c)));
178-
lid += md5.digest('hex');
176+
lid += md5hash(hash.map(x => this.stack.resolve(x)).map(c => JSON.stringify(c)).join(''));
179177
}
180178

181179
return lid;

‎packages/@aws-cdk/aws-ec2/lib/instance.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import * as crypto from 'crypto';
21
import * as iam from '@aws-cdk/aws-iam';
32

43
import { Annotations, Aspects, Duration, Fn, IResource, Lazy, Resource, Stack, Tags } from '@aws-cdk/core';
4+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
55
import { Construct } from 'constructs';
66
import { InstanceRequireImdsv2Aspect } from './aspects';
77
import { CloudFormationInit } from './cfn-init';
@@ -423,14 +423,14 @@ export class Instance extends Resource implements IInstance {
423423
if (recursing) { return originalLogicalId; }
424424
if (!(props.userDataCausesReplacement ?? props.initOptions)) { return originalLogicalId; }
425425

426-
const md5 = crypto.createHash('md5');
426+
const fragments = new Array<string>();
427427
recursing = true;
428428
try {
429-
md5.update(JSON.stringify(context.resolve(this.userData.render())));
429+
fragments.push(JSON.stringify(context.resolve(this.userData.render())));
430430
} finally {
431431
recursing = false;
432432
}
433-
const digest = md5.digest('hex').slice(0, 16);
433+
const digest = md5hash(fragments.join('')).slice(0, 16);
434434
return `${originalLogicalId}${digest}`;
435435
},
436436
}));

‎packages/@aws-cdk/aws-ec2/lib/volume.ts

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import * as crypto from 'crypto';
2-
31
import { AccountRootPrincipal, Grant, IGrantable } from '@aws-cdk/aws-iam';
42
import { IKey, ViaServicePrincipal } from '@aws-cdk/aws-kms';
53
import { IResource, Resource, Size, SizeRoundingBehavior, Stack, Token, Tags, Names, RemovalPolicy } from '@aws-cdk/core';
4+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
65
import { Construct } from 'constructs';
76
import { CfnVolume } from './ec2.generated';
87
import { IInstance } from './instance';
@@ -565,9 +564,7 @@ abstract class VolumeBase extends Resource implements IVolume {
565564
}
566565

567566
private calculateResourceTagValue(constructs: Construct[]): string {
568-
const md5 = crypto.createHash('md5');
569-
constructs.forEach(construct => md5.update(Names.uniqueId(construct)));
570-
return md5.digest('hex');
567+
return md5hash(constructs.map(c => Names.uniqueId(c)).join(''));
571568
}
572569
}
573570

‎packages/@aws-cdk/aws-glue/lib/code.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import * as crypto from 'crypto';
21
import * as fs from 'fs';
32
import * as iam from '@aws-cdk/aws-iam';
43
import * as s3 from '@aws-cdk/aws-s3';
54
import * as s3assets from '@aws-cdk/aws-s3-assets';
65
import * as cdk from '@aws-cdk/core';
6+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
77
import * as constructs from 'constructs';
88

99
/**
@@ -95,9 +95,7 @@ export class AssetCode extends Code {
9595
* Hash a string
9696
*/
9797
private hashcode(s: string): string {
98-
const hash = crypto.createHash('md5');
99-
hash.update(s);
100-
return hash.digest('hex');
98+
return md5hash(s);
10199
};
102100
}
103101

‎packages/@aws-cdk/aws-lambda-event-sources/lib/kafka.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as crypto from 'crypto';
1+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
22
import { ISecurityGroup, IVpc, SubnetSelection } from '@aws-cdk/aws-ec2';
33
import * as iam from '@aws-cdk/aws-iam';
44
import * as lambda from '@aws-cdk/aws-lambda';
@@ -219,9 +219,7 @@ export class SelfManagedKafkaEventSource extends StreamEventSource {
219219
}
220220

221221
private mappingId(target: lambda.IFunction) {
222-
let hash = crypto.createHash('md5');
223-
hash.update(JSON.stringify(Stack.of(target).resolve(this.innerProps.bootstrapServers)));
224-
const idHash = hash.digest('hex');
222+
const idHash = md5hash(JSON.stringify(Stack.of(target).resolve(this.innerProps.bootstrapServers)));
225223
return `KafkaEventSource:${idHash}:${this.innerProps.topic}`;
226224
}
227225

‎packages/@aws-cdk/aws-lambda/lib/function-hash.ts

+3-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import * as crypto from 'crypto';
21
import { CfnResource, FeatureFlags, Stack } from '@aws-cdk/core';
2+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
33
import { LAMBDA_RECOGNIZE_LAYER_VERSION, LAMBDA_RECOGNIZE_VERSION_PROPS } from '@aws-cdk/cx-api';
44
import { Function as LambdaFunction } from './function';
55
import { ILayerVersion } from './layers';
@@ -34,9 +34,7 @@ export function calculateFunctionHash(fn: LambdaFunction) {
3434
stringifiedConfig = stringifiedConfig + calculateLayersHash(fn._layers);
3535
}
3636

37-
const hash = crypto.createHash('md5');
38-
hash.update(stringifiedConfig);
39-
return hash.digest('hex');
37+
return md5hash(stringifiedConfig);
4038
}
4139

4240
export function trimFromStart(s: string, maxLength: number) {
@@ -146,7 +144,5 @@ function calculateLayersHash(layers: ILayerVersion[]): string {
146144
layerConfig[layer.node.id] = properties;
147145
}
148146

149-
const hash = crypto.createHash('md5');
150-
hash.update(JSON.stringify(layerConfig));
151-
return hash.digest('hex');
147+
return md5hash(JSON.stringify(layerConfig));
152148
}

‎packages/@aws-cdk/aws-rds/lib/database-secret.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import * as crypto from 'crypto';
21
import * as kms from '@aws-cdk/aws-kms';
32
import * as secretsmanager from '@aws-cdk/aws-secretsmanager';
43
import { Aws, Names } from '@aws-cdk/core';
4+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
55
import { Construct } from 'constructs';
66
import { DEFAULT_PASSWORD_EXCLUDE_CHARS } from './private/util';
77

@@ -88,14 +88,13 @@ export class DatabaseSecret extends secretsmanager.Secret {
8888
});
8989

9090
if (props.replaceOnPasswordCriteriaChanges) {
91-
const hash = crypto.createHash('md5');
92-
hash.update(JSON.stringify({
91+
const hash = md5hash(JSON.stringify({
9392
// Use here the options that influence the password generation.
9493
// If at some point we add other password customization options
9594
// they sould be added here below (e.g. `passwordLength`).
9695
excludeCharacters,
9796
}));
98-
const logicalId = `${Names.uniqueId(this)}${hash.digest('hex')}`;
97+
const logicalId = `${Names.uniqueId(this)}${hash}`;
9998

10099
const secret = this.node.defaultChild as secretsmanager.CfnSecret;
101100
secret.overrideLogicalId(logicalId.slice(-255)); // Take last 255 chars

‎packages/@aws-cdk/aws-route53-patterns/lib/website-redirect.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as crypto from 'crypto';
1+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
22
import { DnsValidatedCertificate, ICertificate } from '@aws-cdk/aws-certificatemanager';
33
import { CloudFrontWebDistribution, OriginProtocolPolicy, PriceClass, ViewerCertificate, ViewerProtocolPolicy } from '@aws-cdk/aws-cloudfront';
44
import { ARecord, AaaaRecord, IHostedZone, RecordTarget } from '@aws-cdk/aws-route53';
@@ -97,7 +97,7 @@ export class HttpsRedirect extends Construct {
9797
});
9898

9999
domainNames.forEach((domainName) => {
100-
const hash = crypto.createHash('md5').update(domainName).digest('hex').slice(0, 6);
100+
const hash = md5hash(domainName).slice(0, 6);
101101
const aliasProps = {
102102
recordName: domainName,
103103
zone: props.zone,

‎packages/@aws-cdk/aws-route53/lib/vpc-endpoint-service-domain-name.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as crypto from 'crypto';
1+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
22
import { IVpcEndpointService } from '@aws-cdk/aws-ec2';
33
import { Fn, Names, Stack } from '@aws-cdk/core';
44
import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from '@aws-cdk/custom-resources';
@@ -225,7 +225,5 @@ interface PrivateDnsConfiguration {
225225
* Hash a string
226226
*/
227227
function hashcode(s: string): string {
228-
const hash = crypto.createHash('md5');
229-
hash.update(s);
230-
return hash.digest('hex');
228+
return md5hash(s);
231229
};

‎packages/@aws-cdk/aws-sagemaker/lib/private/util.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import * as crypto from 'crypto';
21
import * as cdk from '@aws-cdk/core';
2+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
33

44
/**
55
* Generates a hash from the provided string for the purposes of avoiding construct ID collision
@@ -8,9 +8,7 @@ import * as cdk from '@aws-cdk/core';
88
* @returns A hex string representing the hash of the provided string
99
*/
1010
export function hashcode(s: string): string {
11-
const hash = crypto.createHash('md5');
12-
hash.update(s);
13-
return hash.digest('hex');
11+
return md5hash(s);
1412
}
1513

1614
/**
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
export * from './cfn-parse';
2+
// Other libraries are going to need this as well
3+
export { md5hash } from '../private/md5';
24
export * from './customize-roles';
+200
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/**
2+
* md5 hashing
3+
*
4+
* Uses the built-in 'crypto' library by default for a C implementation
5+
* of md5, but in case the crypto library has been compiled to disable
6+
* FIPS-noncompliant hash suites, fall back to a pure JS implementation of
7+
* md5.
8+
*/
9+
import * as crypto from 'crypto';
10+
11+
let _impl: undefined | ((x: string) => string);
12+
13+
/* eslint-disable no-restricted-syntax */
14+
15+
/**
16+
* Return a hash of the given input string, in hex format
17+
*/
18+
export function md5hash(x: string) {
19+
if (!_impl) {
20+
try {
21+
crypto.createHash('md5');
22+
_impl = cryptoMd5;
23+
} catch (e) {
24+
_impl = jsMd5;
25+
}
26+
}
27+
return _impl(x);
28+
}
29+
30+
/* eslint-disable no-bitwise */
31+
32+
export function cryptoMd5(x: string) {
33+
const hash = crypto.createHash('md5');
34+
hash.update(x);
35+
return hash.digest('hex');
36+
}
37+
38+
export function jsMd5(s: string) {
39+
return hex(md5Buffer(Buffer.from(s, 'utf-8')));
40+
}
41+
42+
function md5Round(x: number[], k: ReadonlyArray<number>) {
43+
let a = x[0], b = x[1], c = x[2], d = x[3];
44+
45+
a = F(a, b, c, d, k[0], 7, -680876936);
46+
d = F(d, a, b, c, k[1], 12, -389564586);
47+
c = F(c, d, a, b, k[2], 17, 606105819);
48+
b = F(b, c, d, a, k[3], 22, -1044525330);
49+
a = F(a, b, c, d, k[4], 7, -176418897);
50+
d = F(d, a, b, c, k[5], 12, 1200080426);
51+
c = F(c, d, a, b, k[6], 17, -1473231341);
52+
b = F(b, c, d, a, k[7], 22, -45705983);
53+
a = F(a, b, c, d, k[8], 7, 1770035416);
54+
d = F(d, a, b, c, k[9], 12, -1958414417);
55+
c = F(c, d, a, b, k[10], 17, -42063);
56+
b = F(b, c, d, a, k[11], 22, -1990404162);
57+
a = F(a, b, c, d, k[12], 7, 1804603682);
58+
d = F(d, a, b, c, k[13], 12, -40341101);
59+
c = F(c, d, a, b, k[14], 17, -1502002290);
60+
b = F(b, c, d, a, k[15], 22, 1236535329);
61+
62+
a = G(a, b, c, d, k[1], 5, -165796510);
63+
d = G(d, a, b, c, k[6], 9, -1069501632);
64+
c = G(c, d, a, b, k[11], 14, 643717713);
65+
b = G(b, c, d, a, k[0], 20, -373897302);
66+
a = G(a, b, c, d, k[5], 5, -701558691);
67+
d = G(d, a, b, c, k[10], 9, 38016083);
68+
c = G(c, d, a, b, k[15], 14, -660478335);
69+
b = G(b, c, d, a, k[4], 20, -405537848);
70+
a = G(a, b, c, d, k[9], 5, 568446438);
71+
d = G(d, a, b, c, k[14], 9, -1019803690);
72+
c = G(c, d, a, b, k[3], 14, -187363961);
73+
b = G(b, c, d, a, k[8], 20, 1163531501);
74+
a = G(a, b, c, d, k[13], 5, -1444681467);
75+
d = G(d, a, b, c, k[2], 9, -51403784);
76+
c = G(c, d, a, b, k[7], 14, 1735328473);
77+
b = G(b, c, d, a, k[12], 20, -1926607734);
78+
79+
a = H(a, b, c, d, k[5], 4, -378558);
80+
d = H(d, a, b, c, k[8], 11, -2022574463);
81+
c = H(c, d, a, b, k[11], 16, 1839030562);
82+
b = H(b, c, d, a, k[14], 23, -35309556);
83+
a = H(a, b, c, d, k[1], 4, -1530992060);
84+
d = H(d, a, b, c, k[4], 11, 1272893353);
85+
c = H(c, d, a, b, k[7], 16, -155497632);
86+
b = H(b, c, d, a, k[10], 23, -1094730640);
87+
a = H(a, b, c, d, k[13], 4, 681279174);
88+
d = H(d, a, b, c, k[0], 11, -358537222);
89+
c = H(c, d, a, b, k[3], 16, -722521979);
90+
b = H(b, c, d, a, k[6], 23, 76029189);
91+
a = H(a, b, c, d, k[9], 4, -640364487);
92+
d = H(d, a, b, c, k[12], 11, -421815835);
93+
c = H(c, d, a, b, k[15], 16, 530742520);
94+
b = H(b, c, d, a, k[2], 23, -995338651);
95+
96+
a = I(a, b, c, d, k[0], 6, -198630844);
97+
d = I(d, a, b, c, k[7], 10, 1126891415);
98+
c = I(c, d, a, b, k[14], 15, -1416354905);
99+
b = I(b, c, d, a, k[5], 21, -57434055);
100+
a = I(a, b, c, d, k[12], 6, 1700485571);
101+
d = I(d, a, b, c, k[3], 10, -1894986606);
102+
c = I(c, d, a, b, k[10], 15, -1051523);
103+
b = I(b, c, d, a, k[1], 21, -2054922799);
104+
a = I(a, b, c, d, k[8], 6, 1873313359);
105+
d = I(d, a, b, c, k[15], 10, -30611744);
106+
c = I(c, d, a, b, k[6], 15, -1560198380);
107+
b = I(b, c, d, a, k[13], 21, 1309151649);
108+
a = I(a, b, c, d, k[4], 6, -145523070);
109+
d = I(d, a, b, c, k[11], 10, -1120210379);
110+
c = I(c, d, a, b, k[2], 15, 718787259);
111+
b = I(b, c, d, a, k[9], 21, -343485551);
112+
113+
x[0] = add32(a, x[0]);
114+
x[1] = add32(b, x[1]);
115+
x[2] = add32(c, x[2]);
116+
x[3] = add32(d, x[3]);
117+
}
118+
119+
function cmn(q: number, a: number, b: number, x: number, s: number, t: number) {
120+
a = add32(add32(a, q), add32(x, t));
121+
return add32((a << s) | (a >>> (32 - s)), b);
122+
}
123+
124+
function F(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
125+
return cmn((b & c) | (~b & d), a, b, x, s, t);
126+
}
127+
128+
function G(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
129+
return cmn((b & d) | (c & ~d), a, b, x, s, t);
130+
}
131+
132+
function H(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
133+
return cmn(b ^ c ^ d, a, b, x, s, t);
134+
}
135+
136+
function I(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
137+
return cmn(c ^ (b | ~d), a, b, x, s, t);
138+
}
139+
140+
function md5Buffer(buf: Buffer) {
141+
let n = buf.length,
142+
state = [1732584193, -271733879, -1732584194, 271733878],
143+
i = 0;
144+
145+
for (; i + 64 <= n; i += 64) {
146+
md5Round(state, bytesToWordsBuf(buf, i));
147+
}
148+
149+
// Padding - a single high 1 byte, and the length of the original message at the end
150+
// Need to add 2 tails if the message is less than 9 bytes shorter than a multiple of 64
151+
// (Otherwise not enough room for high bit and the 64 bit size)
152+
const remainingBytes = n - i;
153+
const padding = Buffer.alloc(64 - remainingBytes < 9 ? 128 : 64);
154+
155+
buf.copy(padding, 0, i);
156+
padding.writeUint8(0x80, remainingBytes); // High bit
157+
158+
const bitLength = n * 8;
159+
padding.writeUint32LE(n << 3, padding.length - 8);
160+
if (bitLength >= 0xFFFFFFFF) {
161+
padding.writeUint32LE(Math.floor(bitLength / 0xFFFFFFFF), padding.length - 4);
162+
}
163+
164+
md5Round(state, bytesToWordsBuf(padding, 0));
165+
if (padding.length > 64) {
166+
md5Round(state, bytesToWordsBuf(padding, 64));
167+
}
168+
169+
return state;
170+
}
171+
172+
function bytesToWordsBuf(buf: Buffer, byteOffset: number) {
173+
const ret = new Array<number>(16);
174+
let i = 0, j = byteOffset;
175+
176+
for (; i < 16; i++, j += 4) {
177+
ret[i] = buf.readUint32LE(j);
178+
}
179+
return ret;
180+
}
181+
182+
let hex_chr = '0123456789abcdef'.split('');
183+
184+
function hexify(n: number) {
185+
const s = new Array<string>();
186+
for (let j = 0; j < 4; j++) {
187+
s.push(hex_chr[(n >>> (j * 8 + 4)) & 0x0f] + hex_chr[(n >>> (j * 8)) & 0x0f]);
188+
}
189+
return s.join('');
190+
}
191+
192+
function hex(x: number[]) {
193+
const ret = new Array<string>(x.length);
194+
for (let i = 0; i < x.length; i++) ret[i] = hexify(x[i]);
195+
return ret.join('');
196+
}
197+
198+
function add32(a: number, b: number) {
199+
return (a + b) & 0xffffffff;
200+
}

‎packages/@aws-cdk/core/lib/private/unique-resource-name.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { createHash } from 'crypto';
2-
// import { unresolved } from './encoding';
1+
import { md5hash } from './md5';
32

43
/**
54
* Options for creating a unique resource name.
@@ -86,7 +85,7 @@ export function makeUniqueResourceName(components: string[], options: MakeUnique
8685
* The hash is limited in size.
8786
*/
8887
function pathHash(path: string[]): string {
89-
const md5 = createHash('md5').update(path.join(PATH_SEP)).digest('hex');
88+
const md5 = md5hash(path.join(PATH_SEP));
9089
return md5.slice(0, HASH_LEN).toUpperCase();
9190
}
9291

‎packages/@aws-cdk/core/lib/private/uniqueid.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import * as crypto from 'crypto';
21
import { unresolved } from './encoding';
2+
import { md5hash } from './md5';
33

44
/**
55
* Resources with this ID are hidden from humans
@@ -76,7 +76,7 @@ export function makeUniqueId(components: string[]) {
7676
* The hash is limited in size.
7777
*/
7878
function pathHash(path: string[]): string {
79-
const md5 = crypto.createHash('md5').update(path.join(PATH_SEP)).digest('hex');
79+
const md5 = md5hash(path.join(PATH_SEP));
8080
return md5.slice(0, HASH_LEN).toUpperCase();
8181
}
8282

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { jsMd5, cryptoMd5 } from '../../lib/private/md5';
2+
3+
test.each([
4+
'',
5+
'asdf',
6+
'hello',
7+
'🤠',
8+
'x'.repeat(54),
9+
'y'.repeat(63),
10+
'z'.repeat(64),
11+
'a'.repeat(64) + 'y',
12+
'b'.repeat(115),
13+
'c'.repeat(128),
14+
])('test md5 equality for %p', s => {
15+
expect(jsMd5(s)).toEqual(cryptoMd5(s));
16+
});
17+
18+
// eslint-disable-next-line jest/no-disabled-tests
19+
test.skip('test md5 equality for a giant string (larger than 512MB)', () => {
20+
const s = 'x'.repeat(515_000_000);
21+
expect(jsMd5(s)).toEqual(cryptoMd5(s));
22+
});
23+
24+
describe('timing', () => {
25+
const s = 'x'.repeat(352321);
26+
const N = 100;
27+
28+
// On my machine:
29+
// - crypto: 73ms
30+
// - native: 1187ms
31+
32+
test('crypto', () => {
33+
for (let i = 0; i < N; i++) {
34+
cryptoMd5(s);
35+
}
36+
});
37+
38+
test('native', () => {
39+
for (let i = 0; i < N; i++) {
40+
jsMd5(s);
41+
}
42+
});
43+
});

‎packages/@aws-cdk/core/test/private/unique-resource-name.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { createHash } from 'crypto';
1+
import { md5hash } from '../../lib/helpers-internal';
22
import { makeUniqueResourceName } from '../../lib/private/unique-resource-name';
33

44
const pathHash = (path: string[]): string => {
5-
return createHash('md5').update(path.join('/')).digest('hex').slice(0, 8).toUpperCase();
5+
return md5hash(path.join('/')).slice(0, 8).toUpperCase();
66
};
77

88
describe('makeUniqueResourceName tests', () => {
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import * as crypto from 'crypto';
1+
import { md5hash as coreMd5 } from '@aws-cdk/core/lib/helpers-internal';
22

33
export function md5hash(obj: any): string {
44
if (!obj || (typeof(obj) === 'object' && Object.keys(obj).length === 0)) {
55
throw new Error('Cannot compute md5 hash for falsy object');
66
}
7-
const hash = crypto.createHash('md5');
8-
hash.update(JSON.stringify(obj));
9-
return hash.digest('hex');
7+
return coreMd5(JSON.stringify(obj));
108
}

‎tools/@aws-cdk/cdk-build-tools/config/eslintrc.js

+10
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,16 @@ module.exports = {
153153
// Are you sure | is not a typo for || ?
154154
'no-bitwise': ['error'],
155155

156+
// No more md5, will break in FIPS environments
157+
"no-restricted-syntax": [
158+
"error",
159+
{
160+
// Both qualified and unqualified calls
161+
"selector": "CallExpression:matches([callee.name='createHash'], [callee.property.name='createHash']) Literal[value='md5']",
162+
"message": "Use the md5hash() function from the core library if you want md5"
163+
}
164+
],
165+
156166
// Oh ho ho naming. Everyone's favorite topic!
157167
// FIXME: there's no way to do this properly. The proposed tslint replacement
158168
// works very differently, also checking names in object literals, which we use all over the

0 commit comments

Comments
 (0)
Please sign in to comment.