diff options
Diffstat (limited to 'std')
-rw-r--r-- | std/hash/sha1.ts | 73 | ||||
-rw-r--r-- | std/hash/sha1_test.ts | 56 |
2 files changed, 126 insertions, 3 deletions
diff --git a/std/hash/sha1.ts b/std/hash/sha1.ts index 19563088b..b30ccb6b6 100644 --- a/std/hash/sha1.ts +++ b/std/hash/sha1.ts @@ -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(); + } + } +} diff --git a/std/hash/sha1_test.ts b/std/hash/sha1_test.ts index 2caaff49b..fae57e2f2 100644 --- a/std/hash/sha1_test.ts +++ b/std/hash/sha1_test.ts @@ -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")); |