以下是使用JavaScript实现HMAC-SHA1签名的方法,不使用外部库(如CryptoJS)。
function hmacSha1(key, message) {
const blocksize = 64; // HMAC-SHA1 block size is 64 bytes
// If the key is longer than blocksize, hash it
if (key.length > blocksize) {
key = sha1(key);
}
// If the key is shorter than blocksize, pad it with zeros
if (key.length < blocksize) {
key = key.concat(new Array(blocksize - key.length).fill(0));
}
// XOR key with inner and outer padding
const ipad = new Array(blocksize).fill(0x36);
const opad = new Array(blocksize).fill(0x5c);
for (let i = 0; i < key.length; i++) {
ipad[i] ^= key[i];
opad[i] ^= key[i];
}
// Perform inner hash
const innerHash = sha1(ipad.concat(message));
// Perform outer hash
return sha1(opad.concat(innerHash));
}
function sha1(message) {
const blocksize = 64; // SHA-1 block size is 64 bytes
const wordsize = 4; // SHA-1 word size is 4 bytes
// Convert message to bytes
if (typeof message === 'string') {
message = unescape(encodeURIComponent(message));
}
const bytes = new Uint8Array(message.length);
for (let i = 0; i < message.length; i++) {
bytes[i] = message.charCodeAt(i);
}
// Append padding
const bitLength = bytes.length * 8;
bytes[bytes.length] = 0x80; // Append 1 bit followed by 7 zeros
let paddingLength = blocksize - ((bytes.length + 8) % blocksize);
paddingLength += paddingLength % wordsize;
const paddingBytes = new Uint8Array(paddingLength + 8);
paddingBytes.set(new Uint8Array([0x00]), 0); // Append zeros
paddingBytes.set(new Uint8Array(bytes.length + 8), paddingLength); // Append bit length
for (let i = 0; i < bytes.length; i++) {
paddingBytes[i] = bytes[i];
}
for (let i = 0; i < 8; i++) {
paddingBytes[paddingBytes.length - 1 - i] = (bitLength >>> (i * 8)) & 0xFF;
}
// Initialize hash values
const h0 = 0x67452301;
const h1 = 0xEFCDAB89;
const h2 = 0x98BADCFE;
const h3 = 0x10325476;
const h4 = 0xC3D2E1F0;
// Helper function
function rotateLeft(n, s) {
return (n << s) | (n >>> (32 - s));
}
// Initialize array of round constants
const k = new Uint32Array([
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6,
]);
// Initialize hash buffer
const buffer = new Uint32Array(blocksize);
buffer[0] = h0;
buffer[1] = h1;
buffer[2] = h2;
buffer[3] = h3;
buffer[4] = h4;
// Main loop
for (let i = 0; i < paddingBytes.length; i += blocksize) {
const words = new Uint32Array(buffer.buffer, 0, 80);
// Copy block into buffer
for (let j = 0; j < blocksize; j++) {
words[j] = (paddingBytes[i + (j * wordsize)] << 24) |
(paddingBytes[i + (j * wordsize) + 1] << 16) |
(paddingBytes[i + (j * wordsize) + 2] << 8) |
(paddingBytes[i + (j * wordsize) + 3]);
}
// Extend the sixteen 32-bit words into eighty 32-bit words
for (let j = 16; j < 80; j++) {
const word = words[j - 3] ^ words[j - 8] ^ words[j - 14] ^ words[j - 16];
words