0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 09:31:22 -05:00

feat(std/hash): add the sha1Hmac (#8418)

This commit is contained in:
silence 2020-11-19 20:09:30 +08:00 committed by GitHub
parent f4ac2b1475
commit e3c3fc58cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 126 additions and 3 deletions

View file

@ -33,6 +33,9 @@ export class Sha1 {
#lastByteIndex = 0;
constructor(sharedMemory = false) {
this.init(sharedMemory);
}
protected init(sharedMemory: boolean) {
if (sharedMemory) {
// deno-fmt-ignore
blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
@ -50,7 +53,6 @@ export class Sha1 {
this.#block = this.#start = this.#bytes = this.#hBytes = 0;
this.#finalized = this.#hashed = false;
}
update(message: Message): this {
if (this.#finalized) {
return this;
@ -121,7 +123,7 @@ export class Sha1 {
return this;
}
private finalize(): void {
protected finalize(): void {
if (this.#finalized) {
return;
}
@ -383,3 +385,70 @@ export class Sha1 {
return buffer;
}
}
export class HmacSha1 extends Sha1 {
#sharedMemory: boolean;
#inner: boolean;
#oKeyPad: number[];
constructor(secretKey: Message, sharedMemory = false) {
super(sharedMemory);
let key: number[] | Uint8Array | undefined;
if (typeof secretKey === "string") {
const bytes: number[] = [];
const length: number = secretKey.length;
let index = 0;
for (let i = 0; i < length; i++) {
let code = secretKey.charCodeAt(i);
if (code < 0x80) {
bytes[index++] = code;
} else if (code < 0x800) {
bytes[index++] = 0xc0 | (code >> 6);
bytes[index++] = 0x80 | (code & 0x3f);
} else if (code < 0xd800 || code >= 0xe000) {
bytes[index++] = 0xe0 | (code >> 12);
bytes[index++] = 0x80 | ((code >> 6) & 0x3f);
bytes[index++] = 0x80 | (code & 0x3f);
} else {
code = 0x10000 +
(((code & 0x3ff) << 10) | (secretKey.charCodeAt(++i) & 0x3ff));
bytes[index++] = 0xf0 | (code >> 18);
bytes[index++] = 0x80 | ((code >> 12) & 0x3f);
bytes[index++] = 0x80 | ((code >> 6) & 0x3f);
bytes[index++] = 0x80 | (code & 0x3f);
}
}
key = bytes;
} else {
if (secretKey instanceof ArrayBuffer) {
key = new Uint8Array(secretKey);
} else {
key = secretKey;
}
}
if (key.length > 64) {
key = new Sha1(true).update(key).array();
}
const oKeyPad: number[] = [];
const iKeyPad: number[] = [];
for (let i = 0; i < 64; i++) {
const b = key[i] || 0;
oKeyPad[i] = 0x5c ^ b;
iKeyPad[i] = 0x36 ^ b;
}
this.update(iKeyPad);
this.#oKeyPad = oKeyPad;
this.#inner = true;
this.#sharedMemory = sharedMemory;
}
protected finalize(): void {
super.finalize();
if (this.#inner) {
this.#inner = false;
const innerHash = this.array();
super.init(this.#sharedMemory);
this.update(this.#oKeyPad);
this.update(innerHash);
super.finalize();
}
}
}

View file

@ -1,6 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { assertEquals } from "../testing/asserts.ts";
import { Message, Sha1 } from "./sha1.ts";
import { HmacSha1, Message, Sha1 } from "./sha1.ts";
import { dirname, fromFileUrl, join, resolve } from "../path/mod.ts";
const moduleDir = dirname(fromFileUrl(import.meta.url));
@ -20,6 +20,7 @@ function toHexString(value: number[] | ArrayBuffer): string {
// deno-fmt-ignore
const fixtures: {
sha1: Record<string, Record<string, Message>>;
sha1Hmac: Record<string, Record<string, [Message, Message]>>;
} = {
sha1: {
"ascii": {
@ -61,6 +62,40 @@ const fixtures: {
'5ba93c9db0cff93f52b521d7420e43f6eda2784f': new ArrayBuffer(1)
}
},
sha1Hmac:{
"Test Vectors": {
"b617318655057264e28bc0b6fb378c8ef146be00": [
[0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b],
"Hi There"
],
"effcdf6ae5eb2fa2d27416d5f184df9c259a7c79": [
"Jefe",
"what do ya want for nothing?"
],
"125d7342b9ac11cd91a39af48aa17b4f63f175d3": [
[0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa],
[0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd]
],
"4c9007f4026250c6bc8414f9bf50c86c2d7235da": [
[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19],
[0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd]
],
"90d0dace1c1bdc957339307803160335bde6df2b": [
[0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa],
"Test Using Larger Than Block-Size Key - Hash Key First"
],
"217e44bb08b6e06a2d6c30f3cb9f537f97c63356": [
[0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa],
"This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm."
]
},
"UTF8": {
"f495de6d0f1b5681070a024bbaed5b5f42847306": ["中文", "中文"],
"58891d68487ffebddba5925abedec77a5a578db2": ["aécio", "aécio"],
"a1816bff2dae324c283aeab564d5edb5170fbada": ["𠜎", "𠜎"]
}
},
};
const methods = ["array", "arrayBuffer", "digest", "hex"] as const;
@ -103,6 +138,25 @@ for (const method of methods) {
}
}
for (const method of methods) {
for (const [name, tests] of Object.entries(fixtures.sha1Hmac)) {
let i = 1;
for (const [expected, [key, message]] of Object.entries(tests)) {
Deno.test({
name: `hmacSha1.${method}() - ${name} - #${i++}`,
fn() {
const algorithm = new HmacSha1(key);
algorithm.update(message);
const actual = method === "hex"
? algorithm[method]()
: toHexString(algorithm[method]());
assertEquals(actual, expected);
},
});
}
}
}
Deno.test("[hash/sha1] test Uint8Array from Reader", async () => {
const data = await Deno.readFile(join(testdataDir, "hashtest"));