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:
parent
f4ac2b1475
commit
e3c3fc58cb
2 changed files with 126 additions and 3 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue