hmac implementation for web crypto
This commit is contained in:
parent
719c8aa70c
commit
81f7bd7b76
|
@ -2,4 +2,5 @@ export abstract class CryptoFunctionService {
|
||||||
pbkdf2: (password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512',
|
pbkdf2: (password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512',
|
||||||
iterations: number, length: number) => Promise<ArrayBuffer>;
|
iterations: number, length: number) => Promise<ArrayBuffer>;
|
||||||
hash: (value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512') => Promise<ArrayBuffer>;
|
hash: (value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512') => Promise<ArrayBuffer>;
|
||||||
|
hmac: (value: ArrayBuffer, key: ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512') => Promise<ArrayBuffer>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,10 @@ export class NodeCryptoFunctionService implements CryptoFunctionService {
|
||||||
return hash.digest().buffer;
|
return hash.digest().buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async hmac(value: ArrayBuffer, key: ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512'): Promise<ArrayBuffer> {
|
||||||
|
return new Uint8Array([]).buffer;
|
||||||
|
}
|
||||||
|
|
||||||
private toNodeValue(value: string | ArrayBuffer): string | Buffer {
|
private toNodeValue(value: string | ArrayBuffer): string | Buffer {
|
||||||
let nodeValue: string | Buffer;
|
let nodeValue: string | Buffer;
|
||||||
if (typeof (value) === 'string') {
|
if (typeof (value) === 'string') {
|
||||||
|
|
|
@ -47,6 +47,21 @@ describe('WebCrypto Function Service', () => {
|
||||||
testHash(true, 'sha256', regular256Hash, utf8256Hash, unicode256Hash);
|
testHash(true, 'sha256', regular256Hash, utf8256Hash, unicode256Hash);
|
||||||
testHash(true, 'sha512', regular512Hash, utf8512Hash, unicode512Hash);
|
testHash(true, 'sha512', regular512Hash, utf8512Hash, unicode512Hash);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('hmac', () => {
|
||||||
|
const sha1Mac = '4d4c223f95dc577b665ec4ccbcb680b80a397038';
|
||||||
|
const sha256Mac = '6be3caa84922e12aaaaa2f16c40d44433bb081ef323db584eb616333ab4e874f';
|
||||||
|
const sha512Mac = '21910e341fa12106ca35758a2285374509326c9fbe0bd64e7b99c898f841dc948c58ce66d3504d8883c' +
|
||||||
|
'5ea7817a0b7c5d4d9b00364ccd214669131fc17fe4aca';
|
||||||
|
|
||||||
|
testHmac(false, 'sha1', sha1Mac);
|
||||||
|
testHmac(false, 'sha256', sha256Mac);
|
||||||
|
testHmac(false, 'sha512', sha512Mac);
|
||||||
|
|
||||||
|
testHmac(true, 'sha1', sha1Mac);
|
||||||
|
testHmac(true, 'sha256', sha256Mac);
|
||||||
|
testHmac(true, 'sha512', sha512Mac);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function testPbkdf2ValidKey(edge: boolean, algorithm: 'sha256' | 'sha512', regularKey: string,
|
function testPbkdf2ValidKey(edge: boolean, algorithm: 'sha256' | 'sha512', regularKey: string,
|
||||||
|
@ -117,6 +132,15 @@ function testHash(edge: boolean, algorithm: 'sha1' | 'sha256' | 'sha512', regula
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testHmac(edge: boolean, algorithm: 'sha1' | 'sha256' | 'sha512', mac: string) {
|
||||||
|
it('should create valid ' + algorithm + ' hmac' + (edge ? ' for edge' : ''), async () => {
|
||||||
|
const webCryptoFunctionService = getWebCryptoFunctionService(edge);
|
||||||
|
const computedMac = await webCryptoFunctionService.hmac(UtilsService.fromUtf8ToArray('SignMe!!').buffer,
|
||||||
|
UtilsService.fromUtf8ToArray('secretkey').buffer, algorithm);
|
||||||
|
expect(UtilsService.fromBufferToHex(computedMac)).toBe(mac);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getWebCryptoFunctionService(edge = false) {
|
function getWebCryptoFunctionService(edge = false) {
|
||||||
const platformUtilsService = new BrowserPlatformUtilsService(edge);
|
const platformUtilsService = new BrowserPlatformUtilsService(edge);
|
||||||
return new WebCryptoFunctionService(window, platformUtilsService);
|
return new WebCryptoFunctionService(window, platformUtilsService);
|
||||||
|
|
|
@ -35,7 +35,7 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
||||||
name: 'PBKDF2',
|
name: 'PBKDF2',
|
||||||
salt: saltBuf,
|
salt: saltBuf,
|
||||||
iterations: iterations,
|
iterations: iterations,
|
||||||
hash: { name: algorithm === 'sha256' ? 'SHA-256' : 'SHA-512' },
|
hash: { name: this.toWebCryptoAlgorithm(algorithm) },
|
||||||
};
|
};
|
||||||
|
|
||||||
const keyType: AesDerivedKeyParams = {
|
const keyType: AesDerivedKeyParams = {
|
||||||
|
@ -65,10 +65,29 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
||||||
|
|
||||||
const valueBuf = this.toBuf(value);
|
const valueBuf = this.toBuf(value);
|
||||||
return await this.subtle.digest({
|
return await this.subtle.digest({
|
||||||
name: algorithm === 'sha1' ? 'SHA-1' : algorithm === 'sha256' ? 'SHA-256' : 'SHA-512'
|
name: this.toWebCryptoAlgorithm(algorithm)
|
||||||
}, valueBuf);
|
}, valueBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async hmac(value: ArrayBuffer, key: ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512'): Promise<ArrayBuffer> {
|
||||||
|
if (this.isEdge) {
|
||||||
|
const valueBytes = this.toForgeBytes(value);
|
||||||
|
const keyBytes = this.toForgeBytes(key);
|
||||||
|
const hmac = (forge as any).hmac.create();
|
||||||
|
hmac.start(algorithm, keyBytes);
|
||||||
|
hmac.update(valueBytes);
|
||||||
|
return this.fromForgeBytesToBuf(hmac.digest().getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
const signingAlgorithm = {
|
||||||
|
name: 'HMAC',
|
||||||
|
hash: { name: this.toWebCryptoAlgorithm(algorithm) },
|
||||||
|
};
|
||||||
|
|
||||||
|
const importedKey = await this.subtle.importKey('raw', key, signingAlgorithm, false, ['sign']);
|
||||||
|
return await this.subtle.sign(signingAlgorithm, importedKey, value);
|
||||||
|
}
|
||||||
|
|
||||||
private toBuf(value: string | ArrayBuffer): ArrayBuffer {
|
private toBuf(value: string | ArrayBuffer): ArrayBuffer {
|
||||||
let buf: ArrayBuffer;
|
let buf: ArrayBuffer;
|
||||||
if (typeof (value) === 'string') {
|
if (typeof (value) === 'string') {
|
||||||
|
@ -94,4 +113,8 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
||||||
const b64 = forge.util.encode64(byteString);
|
const b64 = forge.util.encode64(byteString);
|
||||||
return UtilsService.fromB64ToArray(b64).buffer;
|
return UtilsService.fromB64ToArray(b64).buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private toWebCryptoAlgorithm(algorithm: 'sha1' | 'sha256' | 'sha512'): string {
|
||||||
|
return algorithm === 'sha1' ? 'SHA-1' : algorithm === 'sha256' ? 'SHA-256' : 'SHA-512';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue