mirror of
https://github.com/bitwarden/browser.git
synced 2024-09-10 01:28:36 +02:00
parent
76c09641ba
commit
8cb5a9f505
@ -49,6 +49,45 @@ describe('NodeCrypto Function Service', () => {
|
||||
testPbkdf2('sha512', regular512Key, utf8512Key, unicode512Key);
|
||||
});
|
||||
|
||||
describe('hkdf', () => {
|
||||
const regular256Key = 'qBUmEYtwTwwGPuw/z6bs/qYXXYNUlocFlyAuuANI8Pw=';
|
||||
const utf8256Key = '6DfJwW1R3txgiZKkIFTvVAb7qVlG7lKcmJGJoxR2GBU=';
|
||||
const unicode256Key = 'gejGI82xthA+nKtKmIh82kjw+ttHr+ODsUoGdu5sf0A=';
|
||||
|
||||
const regular512Key = 'xe5cIG6ZfwGmb1FvsOedM0XKOm21myZkjL/eDeKIqqM=';
|
||||
const utf8512Key = 'XQMVBnxVEhlvjSFDQc77j5GDE9aorvbS0vKnjhRg0LY=';
|
||||
const unicode512Key = '148GImrTbrjaGAe/iWEpclINM8Ehhko+9lB14+52lqc=';
|
||||
|
||||
testHkdf('sha256', regular256Key, utf8256Key, unicode256Key);
|
||||
testHkdf('sha512', regular512Key, utf8512Key, unicode512Key);
|
||||
});
|
||||
|
||||
describe('hkdfExpand', () => {
|
||||
const prk16Byte = 'criAmKtfzxanbgea5/kelQ==';
|
||||
const prk32Byte = 'F5h4KdYQnIVH4rKH0P9CZb1GrR4n16/sJrS0PsQEn0Y=';
|
||||
const prk64Byte = 'ssBK0mRG17VHdtsgt8yo4v25CRNpauH+0r2fwY/E9rLyaFBAOMbIeTry+' +
|
||||
'gUJ28p8y+hFh3EI9pcrEWaNvFYonQ=='
|
||||
|
||||
testHkdfExpand('sha256', prk32Byte, 32, 'BnIqJlfnHm0e/2iB/15cbHyR19ARPIcWRp4oNS22CD8=');
|
||||
testHkdfExpand('sha256', prk32Byte, 64, 'BnIqJlfnHm0e/2iB/15cbHyR19ARPIcWRp4oNS22CD9BV+' +
|
||||
'/queOZenPNkDhmlVyL2WZ3OSU5+7ISNF5NhNfvZA==');
|
||||
testHkdfExpand('sha512', prk64Byte, 32, 'uLWbMWodSBms5uGJ5WTRTesyW+MD7nlpCZvagvIRXlk=');
|
||||
testHkdfExpand('sha512', prk64Byte, 64, 'uLWbMWodSBms5uGJ5WTRTesyW+MD7nlpCZvagvIRXlkY5Pv0sB+' +
|
||||
'MqvaopmkC6sD/j89zDwTV9Ib2fpucUydO8w==');
|
||||
|
||||
it('should fail with prk too small', async () => {
|
||||
const cryptoFunctionService = new NodeCryptoFunctionService();
|
||||
const f = cryptoFunctionService.hkdfExpand(Utils.fromB64ToArray(prk16Byte), 'info', 32, 'sha256');
|
||||
await expectAsync(f).toBeRejectedWith(new Error('prk is too small.'));
|
||||
});
|
||||
|
||||
it('should fail with outputByteSize is too large', async () => {
|
||||
const cryptoFunctionService = new NodeCryptoFunctionService();
|
||||
const f = cryptoFunctionService.hkdfExpand(Utils.fromB64ToArray(prk32Byte), 'info', 8161, 'sha256');
|
||||
await expectAsync(f).toBeRejectedWith(new Error('outputByteSize is too large.'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('hash', () => {
|
||||
const regular1Hash = '2a241604fb921fad12bf877282457268e1dccb70';
|
||||
const utf81Hash = '85672798dc5831e96d6c48655d3d39365a9c88b6';
|
||||
@ -234,6 +273,55 @@ function testPbkdf2(algorithm: 'sha256' | 'sha512', regularKey: string, utf8Key:
|
||||
});
|
||||
}
|
||||
|
||||
function testHkdf(algorithm: 'sha256' | 'sha512', regularKey: string, utf8Key: string, unicodeKey: string) {
|
||||
const ikm = Utils.fromB64ToArray('criAmKtfzxanbgea5/kelQ==');
|
||||
|
||||
const regularSalt = 'salt';
|
||||
const utf8Salt = 'üser_salt';
|
||||
const unicodeSalt = '😀salt🙏';
|
||||
|
||||
const regularInfo = 'info';
|
||||
const utf8Info = 'üser_info';
|
||||
const unicodeInfo = '😀info🙏';
|
||||
|
||||
it('should create valid ' + algorithm + ' key from regular input', async () => {
|
||||
const cryptoFunctionService = new NodeCryptoFunctionService();
|
||||
const key = await cryptoFunctionService.hkdf(ikm, regularSalt, regularInfo, 32, algorithm);
|
||||
expect(Utils.fromBufferToB64(key)).toBe(regularKey);
|
||||
});
|
||||
|
||||
it('should create valid ' + algorithm + ' key from utf8 input', async () => {
|
||||
const cryptoFunctionService = new NodeCryptoFunctionService();
|
||||
const key = await cryptoFunctionService.hkdf(ikm, utf8Salt, utf8Info, 32, algorithm);
|
||||
expect(Utils.fromBufferToB64(key)).toBe(utf8Key);
|
||||
});
|
||||
|
||||
it('should create valid ' + algorithm + ' key from unicode input', async () => {
|
||||
const cryptoFunctionService = new NodeCryptoFunctionService();
|
||||
const key = await cryptoFunctionService.hkdf(ikm, unicodeSalt, unicodeInfo, 32, algorithm);
|
||||
expect(Utils.fromBufferToB64(key)).toBe(unicodeKey);
|
||||
});
|
||||
|
||||
it('should create valid ' + algorithm + ' key from array buffer input', async () => {
|
||||
const cryptoFunctionService = new NodeCryptoFunctionService();
|
||||
const key = await cryptoFunctionService.hkdf(ikm, Utils.fromUtf8ToArray(regularSalt).buffer,
|
||||
Utils.fromUtf8ToArray(regularInfo).buffer, 32, algorithm);
|
||||
expect(Utils.fromBufferToB64(key)).toBe(regularKey);
|
||||
});
|
||||
}
|
||||
|
||||
function testHkdfExpand(algorithm: 'sha256' | 'sha512', b64prk: string, outputByteSize: number,
|
||||
b64ExpectedOkm: string) {
|
||||
const info = 'info';
|
||||
|
||||
it('should create valid ' + algorithm + ' ' + outputByteSize + ' byte okm', async () => {
|
||||
const cryptoFunctionService = new NodeCryptoFunctionService();
|
||||
const okm = await cryptoFunctionService.hkdfExpand(Utils.fromB64ToArray(b64prk), info, outputByteSize,
|
||||
algorithm);
|
||||
expect(Utils.fromBufferToB64(okm)).toBe(b64ExpectedOkm);
|
||||
});
|
||||
}
|
||||
|
||||
function testHash(algorithm: 'sha1' | 'sha256' | 'sha512' | 'md5', regularHash: string,
|
||||
utf8Hash: string, unicodeHash: string) {
|
||||
const regularValue = 'HashMe!!';
|
||||
|
@ -53,6 +53,45 @@ describe('WebCrypto Function Service', () => {
|
||||
testPbkdf2('sha512', regular512Key, utf8512Key, unicode512Key);
|
||||
});
|
||||
|
||||
describe('hkdf', () => {
|
||||
const regular256Key = 'qBUmEYtwTwwGPuw/z6bs/qYXXYNUlocFlyAuuANI8Pw=';
|
||||
const utf8256Key = '6DfJwW1R3txgiZKkIFTvVAb7qVlG7lKcmJGJoxR2GBU=';
|
||||
const unicode256Key = 'gejGI82xthA+nKtKmIh82kjw+ttHr+ODsUoGdu5sf0A=';
|
||||
|
||||
const regular512Key = 'xe5cIG6ZfwGmb1FvsOedM0XKOm21myZkjL/eDeKIqqM=';
|
||||
const utf8512Key = 'XQMVBnxVEhlvjSFDQc77j5GDE9aorvbS0vKnjhRg0LY=';
|
||||
const unicode512Key = '148GImrTbrjaGAe/iWEpclINM8Ehhko+9lB14+52lqc=';
|
||||
|
||||
testHkdf('sha256', regular256Key, utf8256Key, unicode256Key);
|
||||
testHkdf('sha512', regular512Key, utf8512Key, unicode512Key);
|
||||
});
|
||||
|
||||
describe('hkdfExpand', () => {
|
||||
const prk16Byte = 'criAmKtfzxanbgea5/kelQ==';
|
||||
const prk32Byte = 'F5h4KdYQnIVH4rKH0P9CZb1GrR4n16/sJrS0PsQEn0Y=';
|
||||
const prk64Byte = 'ssBK0mRG17VHdtsgt8yo4v25CRNpauH+0r2fwY/E9rLyaFBAOMbIeTry+' +
|
||||
'gUJ28p8y+hFh3EI9pcrEWaNvFYonQ=='
|
||||
|
||||
testHkdfExpand('sha256', prk32Byte, 32, 'BnIqJlfnHm0e/2iB/15cbHyR19ARPIcWRp4oNS22CD8=');
|
||||
testHkdfExpand('sha256', prk32Byte, 64, 'BnIqJlfnHm0e/2iB/15cbHyR19ARPIcWRp4oNS22CD9BV+' +
|
||||
'/queOZenPNkDhmlVyL2WZ3OSU5+7ISNF5NhNfvZA==');
|
||||
testHkdfExpand('sha512', prk64Byte, 32, 'uLWbMWodSBms5uGJ5WTRTesyW+MD7nlpCZvagvIRXlk=');
|
||||
testHkdfExpand('sha512', prk64Byte, 64, 'uLWbMWodSBms5uGJ5WTRTesyW+MD7nlpCZvagvIRXlkY5Pv0sB+' +
|
||||
'MqvaopmkC6sD/j89zDwTV9Ib2fpucUydO8w==');
|
||||
|
||||
it('should fail with prk too small', async () => {
|
||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||
const f = cryptoFunctionService.hkdfExpand(Utils.fromB64ToArray(prk16Byte), 'info', 32, 'sha256');
|
||||
await expectAsync(f).toBeRejectedWith(new Error('prk is too small.'));
|
||||
});
|
||||
|
||||
it('should fail with outputByteSize is too large', async () => {
|
||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||
const f = cryptoFunctionService.hkdfExpand(Utils.fromB64ToArray(prk32Byte), 'info', 8161, 'sha256');
|
||||
await expectAsync(f).toBeRejectedWith(new Error('outputByteSize is too large.'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('hash', () => {
|
||||
const regular1Hash = '2a241604fb921fad12bf877282457268e1dccb70';
|
||||
const utf81Hash = '85672798dc5831e96d6c48655d3d39365a9c88b6';
|
||||
@ -318,6 +357,55 @@ function testPbkdf2(algorithm: 'sha256' | 'sha512', regularKey: string,
|
||||
});
|
||||
}
|
||||
|
||||
function testHkdf(algorithm: 'sha256' | 'sha512', regularKey: string, utf8Key: string, unicodeKey: string) {
|
||||
const ikm = Utils.fromB64ToArray('criAmKtfzxanbgea5/kelQ==');
|
||||
|
||||
const regularSalt = 'salt';
|
||||
const utf8Salt = 'üser_salt';
|
||||
const unicodeSalt = '😀salt🙏';
|
||||
|
||||
const regularInfo = 'info';
|
||||
const utf8Info = 'üser_info';
|
||||
const unicodeInfo = '😀info🙏';
|
||||
|
||||
it('should create valid ' + algorithm + ' key from regular input', async () => {
|
||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||
const key = await cryptoFunctionService.hkdf(ikm, regularSalt, regularInfo, 32, algorithm);
|
||||
expect(Utils.fromBufferToB64(key)).toBe(regularKey);
|
||||
});
|
||||
|
||||
it('should create valid ' + algorithm + ' key from utf8 input', async () => {
|
||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||
const key = await cryptoFunctionService.hkdf(ikm, utf8Salt, utf8Info, 32, algorithm);
|
||||
expect(Utils.fromBufferToB64(key)).toBe(utf8Key);
|
||||
});
|
||||
|
||||
it('should create valid ' + algorithm + ' key from unicode input', async () => {
|
||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||
const key = await cryptoFunctionService.hkdf(ikm, unicodeSalt, unicodeInfo, 32, algorithm);
|
||||
expect(Utils.fromBufferToB64(key)).toBe(unicodeKey);
|
||||
});
|
||||
|
||||
it('should create valid ' + algorithm + ' key from array buffer input', async () => {
|
||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||
const key = await cryptoFunctionService.hkdf(ikm, Utils.fromUtf8ToArray(regularSalt).buffer,
|
||||
Utils.fromUtf8ToArray(regularInfo).buffer, 32, algorithm);
|
||||
expect(Utils.fromBufferToB64(key)).toBe(regularKey);
|
||||
});
|
||||
}
|
||||
|
||||
function testHkdfExpand(algorithm: 'sha256' | 'sha512', b64prk: string, outputByteSize: number,
|
||||
b64ExpectedOkm: string) {
|
||||
const info = 'info';
|
||||
|
||||
it('should create valid ' + algorithm + ' ' + outputByteSize + ' byte okm', async () => {
|
||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||
const okm = await cryptoFunctionService.hkdfExpand(Utils.fromB64ToArray(b64prk), info, outputByteSize,
|
||||
algorithm);
|
||||
expect(Utils.fromBufferToB64(okm)).toBe(b64ExpectedOkm);
|
||||
});
|
||||
}
|
||||
|
||||
function testHash(algorithm: 'sha1' | 'sha256' | 'sha512' | 'md5', regularHash: string,
|
||||
utf8Hash: string, unicodeHash: string) {
|
||||
const regularValue = 'HashMe!!';
|
||||
|
@ -4,6 +4,10 @@ import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
|
||||
export abstract class CryptoFunctionService {
|
||||
pbkdf2: (password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512',
|
||||
iterations: number) => Promise<ArrayBuffer>;
|
||||
hkdf: (ikm: ArrayBuffer, salt: string | ArrayBuffer, info: string | ArrayBuffer,
|
||||
outputByteSize: number, algorithm: 'sha256' | 'sha512') => Promise<ArrayBuffer>
|
||||
hkdfExpand: (prk: ArrayBuffer, info: string | ArrayBuffer, outputByteSize: number,
|
||||
algorithm: 'sha256' | 'sha512') => Promise<ArrayBuffer>;
|
||||
hash: (value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512' | 'md5') => Promise<ArrayBuffer>;
|
||||
hmac: (value: ArrayBuffer, key: ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512') => Promise<ArrayBuffer>;
|
||||
compare: (a: ArrayBuffer, b: ArrayBuffer) => Promise<boolean>;
|
||||
|
@ -182,8 +182,8 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
throw new Error('No public key available.');
|
||||
}
|
||||
const keyFingerprint = await this.cryptoFunctionService.hash(publicKey, 'sha256');
|
||||
const userFingerprint = await this.hkdfExpand(keyFingerprint, Utils.fromUtf8ToArray(userId), 32);
|
||||
return this.hashPhrase(userFingerprint.buffer);
|
||||
const userFingerprint = await this.cryptoFunctionService.hkdfExpand(keyFingerprint, userId, 32, 'sha256');
|
||||
return this.hashPhrase(userFingerprint);
|
||||
}
|
||||
|
||||
@sequentialize(() => 'getOrgKeys')
|
||||
@ -679,28 +679,13 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
|
||||
private async stretchKey(key: SymmetricCryptoKey): Promise<SymmetricCryptoKey> {
|
||||
const newKey = new Uint8Array(64);
|
||||
newKey.set(await this.hkdfExpand(key.key, Utils.fromUtf8ToArray('enc'), 32));
|
||||
newKey.set(await this.hkdfExpand(key.key, Utils.fromUtf8ToArray('mac'), 32), 32);
|
||||
const encKey = await this.cryptoFunctionService.hkdfExpand(key.key, 'enc', 32, 'sha256');
|
||||
const macKey = await this.cryptoFunctionService.hkdfExpand(key.key, 'mac', 32, 'sha256');
|
||||
newKey.set(new Uint8Array(encKey));
|
||||
newKey.set(new Uint8Array(macKey), 32);
|
||||
return new SymmetricCryptoKey(newKey.buffer);
|
||||
}
|
||||
|
||||
// ref: https://tools.ietf.org/html/rfc5869
|
||||
private async hkdfExpand(prk: ArrayBuffer, info: Uint8Array, size: number) {
|
||||
const hashLen = 32; // sha256
|
||||
const okm = new Uint8Array(size);
|
||||
let previousT = new Uint8Array(0);
|
||||
const n = Math.ceil(size / hashLen);
|
||||
for (let i = 0; i < n; i++) {
|
||||
const t = new Uint8Array(previousT.length + info.length + 1);
|
||||
t.set(previousT);
|
||||
t.set(info, previousT.length);
|
||||
t.set([i + 1], t.length - 1);
|
||||
previousT = new Uint8Array(await this.cryptoFunctionService.hmac(t.buffer, prk, 'sha256'));
|
||||
okm.set(previousT, i * hashLen);
|
||||
}
|
||||
return okm;
|
||||
}
|
||||
|
||||
private async hashPhrase(hash: ArrayBuffer, minimumEntropy: number = 64) {
|
||||
const entropyPerWord = Math.log(EEFLongWordList.length) / Math.log(2);
|
||||
let numWords = Math.ceil(minimumEntropy / entropyPerWord);
|
||||
|
@ -26,6 +26,46 @@ export class NodeCryptoFunctionService implements CryptoFunctionService {
|
||||
});
|
||||
}
|
||||
|
||||
// ref: https://tools.ietf.org/html/rfc5869
|
||||
async hkdf(ikm: ArrayBuffer, salt: string | ArrayBuffer, info: string | ArrayBuffer,
|
||||
outputByteSize: number, algorithm: 'sha256' | 'sha512'): Promise<ArrayBuffer> {
|
||||
const saltBuf = this.toArrayBuffer(salt);
|
||||
const prk = await this.hmac(ikm, saltBuf, algorithm);
|
||||
return this.hkdfExpand(prk, info, outputByteSize, algorithm);
|
||||
}
|
||||
|
||||
// ref: https://tools.ietf.org/html/rfc5869
|
||||
async hkdfExpand(prk: ArrayBuffer, info: string | ArrayBuffer, outputByteSize: number,
|
||||
algorithm: 'sha256' | 'sha512'): Promise<ArrayBuffer> {
|
||||
const hashLen = algorithm === 'sha256' ? 32 : 64;
|
||||
if (outputByteSize > 255 * hashLen) {
|
||||
throw new Error('outputByteSize is too large.');
|
||||
}
|
||||
const prkArr = new Uint8Array(prk);
|
||||
if (prkArr.length < hashLen) {
|
||||
throw new Error('prk is too small.');
|
||||
}
|
||||
const infoBuf = this.toArrayBuffer(info);
|
||||
const infoArr = new Uint8Array(infoBuf);
|
||||
let runningOkmLength = 0;
|
||||
let previousT = new Uint8Array(0);
|
||||
const n = Math.ceil(outputByteSize / hashLen);
|
||||
const okm = new Uint8Array(n * hashLen);
|
||||
for (let i = 0; i < n; i++) {
|
||||
const t = new Uint8Array(previousT.length + infoArr.length + 1);
|
||||
t.set(previousT);
|
||||
t.set(infoArr, previousT.length);
|
||||
t.set([i + 1], t.length - 1);
|
||||
previousT = new Uint8Array(await this.hmac(t.buffer, prk, algorithm));
|
||||
okm.set(previousT, runningOkmLength);
|
||||
runningOkmLength += previousT.length;
|
||||
if (runningOkmLength >= outputByteSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return okm.slice(0, outputByteSize).buffer;
|
||||
}
|
||||
|
||||
hash(value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512' | 'md5'): Promise<ArrayBuffer> {
|
||||
const nodeValue = this.toNodeValue(value);
|
||||
const hash = crypto.createHash(algorithm);
|
||||
@ -196,8 +236,14 @@ export class NodeCryptoFunctionService implements CryptoFunctionService {
|
||||
return Buffer.from(new Uint8Array(value) as any);
|
||||
}
|
||||
|
||||
private toArrayBuffer(buf: Buffer): ArrayBuffer {
|
||||
return new Uint8Array(buf).buffer;
|
||||
private toArrayBuffer(value: Buffer | string | ArrayBuffer): ArrayBuffer {
|
||||
let buf: ArrayBuffer;
|
||||
if (typeof (value) === 'string') {
|
||||
buf = Utils.fromUtf8ToArray(value).buffer;
|
||||
} else {
|
||||
buf = new Uint8Array(value).buffer;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
private toPemPrivateKey(key: ArrayBuffer): string {
|
||||
|
@ -49,6 +49,55 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
||||
return await this.subtle.deriveBits(pbkdf2Params, impKey, wcLen);
|
||||
}
|
||||
|
||||
async hkdf(ikm: ArrayBuffer, salt: string | ArrayBuffer, info: string | ArrayBuffer,
|
||||
outputByteSize: number, algorithm: 'sha256' | 'sha512'): Promise<ArrayBuffer> {
|
||||
const saltBuf = this.toBuf(salt);
|
||||
const infoBuf = this.toBuf(info);
|
||||
|
||||
const hkdfParams: HkdfParams = {
|
||||
name: 'HKDF',
|
||||
salt: saltBuf,
|
||||
info: infoBuf,
|
||||
hash: { name: this.toWebCryptoAlgorithm(algorithm) },
|
||||
};
|
||||
|
||||
const impKey = await this.subtle.importKey('raw', ikm, { name: 'HKDF' } as any,
|
||||
false, ['deriveBits']);
|
||||
return await this.subtle.deriveBits(hkdfParams as any, impKey, outputByteSize * 8);
|
||||
}
|
||||
|
||||
// ref: https://tools.ietf.org/html/rfc5869
|
||||
async hkdfExpand(prk: ArrayBuffer, info: string | ArrayBuffer, outputByteSize: number,
|
||||
algorithm: 'sha256' | 'sha512'): Promise<ArrayBuffer> {
|
||||
const hashLen = algorithm === 'sha256' ? 32 : 64;
|
||||
if (outputByteSize > 255 * hashLen) {
|
||||
throw new Error('outputByteSize is too large.');
|
||||
}
|
||||
const prkArr = new Uint8Array(prk);
|
||||
if (prkArr.length < hashLen) {
|
||||
throw new Error('prk is too small.');
|
||||
}
|
||||
const infoBuf = this.toBuf(info);
|
||||
const infoArr = new Uint8Array(infoBuf);
|
||||
let runningOkmLength = 0;
|
||||
let previousT = new Uint8Array(0);
|
||||
const n = Math.ceil(outputByteSize / hashLen);
|
||||
const okm = new Uint8Array(n * hashLen);
|
||||
for (let i = 0; i < n; i++) {
|
||||
const t = new Uint8Array(previousT.length + infoArr.length + 1);
|
||||
t.set(previousT);
|
||||
t.set(infoArr, previousT.length);
|
||||
t.set([i + 1], t.length - 1);
|
||||
previousT = new Uint8Array(await this.hmac(t.buffer, prk, algorithm));
|
||||
okm.set(previousT, runningOkmLength);
|
||||
runningOkmLength += previousT.length;
|
||||
if (runningOkmLength >= outputByteSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return okm.slice(0, outputByteSize).buffer;
|
||||
}
|
||||
|
||||
async hash(value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512' | 'md5'): Promise<ArrayBuffer> {
|
||||
if ((this.isIE && algorithm === 'sha1') || algorithm === 'md5') {
|
||||
const md = algorithm === 'md5' ? forge.md.md5.create() : forge.md.sha1.create();
|
||||
|
Loading…
Reference in New Issue
Block a user