diff --git a/package-lock.json b/package-lock.json
index cd5a3a0..fb8195c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
"version": "0.0.0",
"dependencies": {
"gm-crypto": "*",
+ "gmsm-sm3js": "^0.2.0",
"gmsm-sm4js": "^0.7.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@@ -4281,6 +4282,15 @@
"to-arraybuffer": "^1.0.1"
}
},
+ "node_modules/gmsm-sm3js": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmmirror.com/gmsm-sm3js/-/gmsm-sm3js-0.2.0.tgz",
+ "integrity": "sha512-z4SZH+xoQtYSIp22qwwZ0Z45Fajaxav+Y2OGlEoAVm2tK+o0fOQHowPeh91FpCCH/+p0jNiKL2G9C4T9EEQJWA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "long": "^5.2.3"
+ }
+ },
"node_modules/gmsm-sm4js": {
"version": "0.7.0",
"resolved": "https://registry.npmmirror.com/gmsm-sm4js/-/gmsm-sm4js-0.7.0.tgz",
@@ -5467,6 +5477,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/long": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmmirror.com/long/-/long-5.3.2.tgz",
+ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
+ "license": "Apache-2.0"
+ },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz",
diff --git a/package.json b/package.json
index f037fbe..dafca55 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
},
"dependencies": {
"gm-crypto": "*",
+ "gmsm-sm3js": "^0.2.0",
"gmsm-sm4js": "^0.7.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/src/App.tsx b/src/App.tsx
index 011ee7e..577baa0 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react'
import { generateSm2KeyPair, sm2Encrypt, sm2Decrypt } from './utils/algorithm/sm2'
-import { sm3Digest } from './utils/algorithm/sm3'
+import { sm3Digest, sm3Hmac } from './utils/algorithm/sm3'
import { sm4Encrypt, sm4Decrypt } from './utils/algorithm/sm4'
import { hexToUtf8, utf8ToHex } from './utils/convert'
@@ -19,6 +19,7 @@ function App() {
const [sm3Message, setSm3Message] = useState('')
const [sm3Result, setSm3Result] = useState('')
const [sm3MacKey, setSm3MacKey] = useState('')
+ const [sm3MacResult, setSm3MacResult] = useState('')
// SM4 状态
const [sm4Key, setSm4Key] = useState('')
@@ -107,10 +108,10 @@ function App() {
// SM3 MAC 计算
const calculateSm3Mac = () => {
try {
- // 简化处理,实际项目中可能需要使用正确的 API
- alert('MAC 计算功能需要正确的 API 支持')
+ const result = sm3Hmac(sm3MacKey, sm3Message)
+ setSm3MacResult(result)
} catch (error) {
- alert('MAC 计算失败: ' + error)
+ alert('MAC 计算失败: ' + (error instanceof Error ? error.message : error))
}
}
@@ -299,6 +300,7 @@ function App() {
diff --git a/src/__tests__/algorithm/sm3.test.ts b/src/__tests__/algorithm/sm3.test.ts
index aa570c6..9525544 100644
--- a/src/__tests__/algorithm/sm3.test.ts
+++ b/src/__tests__/algorithm/sm3.test.ts
@@ -1,4 +1,4 @@
-import { sm3Digest } from '../../utils/algorithm/sm3'
+import { sm3Digest, sm3Hmac } from '../../utils/algorithm/sm3'
// UTF8 转 Hex
const utf8ToHex = (utf8: string): string => {
@@ -33,3 +33,44 @@ describe('SM3 算法测试', () => {
expect(result1).not.toBe(result2)
})
})
+
+describe('SM3 HMAC 算法测试', () => {
+ test('计算 SM3 HMAC', () => {
+ const key = '0123456789abcdef'
+ const originalMessage = '测试消息'
+ const messageHex = utf8ToHex(originalMessage)
+ const result = sm3Hmac(key, messageHex)
+ expect(result).toBeTruthy()
+ expect(result.length).toBe(64) // SM3 HMAC 结果为 256 位,即 64 个十六进制字符
+ })
+
+ test('相同 key 和消息应该产生相同的 HMAC', () => {
+ const key = '0123456789abcdef'
+ const originalMessage = '测试消息'
+ const messageHex = utf8ToHex(originalMessage)
+ const result1 = sm3Hmac(key, messageHex)
+ const result2 = sm3Hmac(key, messageHex)
+ expect(result1).toBe(result2)
+ })
+
+ test('不同消息应该产生不同的 HMAC', () => {
+ const key = '0123456789abcdef'
+ const originalMessage1 = '测试消息1'
+ const originalMessage2 = '测试消息2'
+ const messageHex1 = utf8ToHex(originalMessage1)
+ const messageHex2 = utf8ToHex(originalMessage2)
+ const result1 = sm3Hmac(key, messageHex1)
+ const result2 = sm3Hmac(key, messageHex2)
+ expect(result1).not.toBe(result2)
+ })
+
+ test('不同 key 应该产生不同的 HMAC', () => {
+ const key1 = '0123456789abcdef'
+ const key2 = 'fedcba9876543210'
+ const originalMessage = '测试消息'
+ const messageHex = utf8ToHex(originalMessage)
+ const result1 = sm3Hmac(key1, messageHex)
+ const result2 = sm3Hmac(key2, messageHex)
+ expect(result1).not.toBe(result2)
+ })
+})
diff --git a/src/utils/algorithm/sm3.ts b/src/utils/algorithm/sm3.ts
index 04d5b00..873122c 100644
--- a/src/utils/algorithm/sm3.ts
+++ b/src/utils/algorithm/sm3.ts
@@ -1,16 +1,10 @@
-import { SM3 } from 'gm-crypto'
+import { sumHex, fromHex } from 'gmsm-sm3js'
// 验证是否为有效的 hex 字符串
const isValidHex = (hex: string): boolean => {
return /^[0-9a-fA-F]*$/.test(hex) && hex.length % 2 === 0
}
-// ArrayBuffer 转 hex 字符串
-const arrayBufferToHex = (buffer: ArrayBuffer): string => {
- const bytes = new Uint8Array(buffer)
- return Array.from(bytes).map(byte => byte.toString(16).padStart(2, '0')).join('')
-}
-
// SM3 计算
export const sm3Digest = (message: string): string => {
try {
@@ -21,17 +15,81 @@ export const sm3Digest = (message: string): string => {
console.log('Input hex message:', message)
- // 直接使用 hex 字符串计算 SM3
- const result = SM3.digest(message, 'hex')
+ // 将 hex 字符串转换为 Uint8Array
+ const messageBytes = fromHex(message)
+
+ // 使用 gmsm-sm3js 计算 SM3
+ const result = sumHex(messageBytes)
console.log('SM3 result:', result)
- // 处理返回结果
- const hexResult = typeof result === 'string' ? result : arrayBufferToHex(result)
- console.log('Hex result:', hexResult)
-
- return hexResult
+ return result
} catch (error) {
console.error('SM3 digest error:', error)
throw error
}
}
+
+// HMAC-SM3 计算
+export const sm3Hmac = (key: string, message: string): string => {
+ try {
+ // 验证 key 和 message 是否为有效的 hex 字符串
+ if (!isValidHex(key)) {
+ throw new Error('Invalid key: must be hex string')
+ }
+ if (!isValidHex(message)) {
+ throw new Error('Invalid message: must be hex string')
+ }
+
+ console.log('Input key:', key)
+ console.log('Input message:', message)
+
+ // 将 hex 字符串转换为 Uint8Array
+ const keyBytes = fromHex(key)
+ const messageBytes = fromHex(message)
+
+ // 实现 HMAC-SM3 算法
+ const blockSize = 64 // SM3 块大小为 512 位 = 64 字节
+
+ // 处理密钥
+ let k: Uint8Array
+ if (keyBytes.length > blockSize) {
+ // 如果密钥长度超过块大小,对密钥进行 SM3 哈希
+ k = fromHex(sumHex(keyBytes))
+ } else {
+ // 否则,用 0 填充到块大小
+ k = new Uint8Array(blockSize)
+ k.set(keyBytes)
+ }
+
+ // 计算 inner padding
+ const ipad = new Uint8Array(blockSize)
+ for (let i = 0; i < blockSize; i++) {
+ ipad[i] = k[i] ^ 0x36
+ }
+
+ // 计算 outer padding
+ const opad = new Uint8Array(blockSize)
+ for (let i = 0; i < blockSize; i++) {
+ opad[i] = k[i] ^ 0x5c
+ }
+
+ // 计算 inner hash: SM3(ipad || message)
+ const innerData = new Uint8Array(ipad.length + messageBytes.length)
+ innerData.set(ipad)
+ innerData.set(messageBytes, ipad.length)
+ const innerHash = fromHex(sumHex(innerData))
+
+ // 计算 outer hash: SM3(opad || innerHash)
+ const outerData = new Uint8Array(opad.length + innerHash.length)
+ outerData.set(opad)
+ outerData.set(innerHash, opad.length)
+ const result = sumHex(outerData)
+
+ console.log('SM3 HMAC result:', result)
+
+ return result
+ } catch (error) {
+ console.error('SM3 HMAC error:', error)
+ throw error
+ }
+}