Compare commits
2 Commits
ffd4d17f5d
...
a7aef0f7dd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7aef0f7dd | ||
|
|
fe1f7c14b4 |
45
docs/sm3-testcases.md
Normal file
45
docs/sm3-testcases.md
Normal file
@ -0,0 +1,45 @@
|
||||
# SM3 测试用例
|
||||
|
||||
## 测试用例列表
|
||||
|
||||
### sm3-001
|
||||
- **输入**: "616263" ("abc" 的 hex 表示)
|
||||
- **预期输出**: "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0"
|
||||
|
||||
### sm3-002
|
||||
- **输入**: "6162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364" ("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd" 的 hex 表示)
|
||||
- **预期输出**: "debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732"
|
||||
|
||||
### sm3-003
|
||||
- **输入**: "6162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364" (长字符串的 hex 表示)
|
||||
- **预期输出**: "6888fa292df4b51341e82e3072fbdd63598439c64eda318a81756ca71a7a6c15"
|
||||
|
||||
### sm3-004
|
||||
- **来源**: [GBT.32918.2-2016] A.2 Example 1
|
||||
- **输入**: "0090414C494345313233405941484F4F2E434F4D787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E49863E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A20AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857"
|
||||
- **预期输出**: "f4a38489e32b45b6f876e3ac2168ca392362dc8f23459c1d1146fc3dbfb7bc9a"
|
||||
|
||||
### sm3-005
|
||||
- **来源**: [GBT.32918.2-2016] A.2 Example 2
|
||||
- **输入**: "F4A38489E32B45B6F876E3AC2168CA392362DC8F23459C1D1146FC3DBFB7BC9A6D65737361676520646967657374"
|
||||
- **预期输出**: "b524f552cd82b8b028476e005c377fb19a87e6fc682d48bb5d42e3d9b9effe76"
|
||||
|
||||
### sm3-006
|
||||
- **来源**: GB/T 32918.2-2016 A.3 Example 1
|
||||
- **输入**: "0090414C494345313233405941484F4F2E434F4D00000000000000000000000000000000000000000000000000000000000000000000E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E0165961645281A8626607B917F657D7E9382F1EA5CD931F40F6627F357542653B201686522130D590FB8DE635D8FCA715CC6BF3D05BEF3F75DA5D543454448166612"
|
||||
- **预期输出**: "26352af82ec19f207bbc6f9474e11e90ce0f7ddace03b27f801817e897a81fd5"
|
||||
|
||||
### sm3-007
|
||||
- **来源**: [GBT.32918.2-2016] A.3 Example 2
|
||||
- **输入**: "26352AF82EC19F207BBC6F9474E11E90CE0F7DDACE03B27F801817E897A81FD56D65737361676520646967657374"
|
||||
- **预期输出**: "ad673cbda311417129a9eaa5f9ab1aa1633ad47718a84dfd46c17c6fa0aa3b12"
|
||||
|
||||
### sm3-008
|
||||
- **来源**: GB/T 32918.4-2016 A.3 Example 1
|
||||
- **输入**: "01C6271B31F6BE396A4166C0616CF4A8ACDA5BEF4DCBF2DD42656E6372797074696F6E207374616E646172640147AF35DFA1BFE2F161521BCF59BAB83564868D9295881735"
|
||||
- **预期输出**: "f0a41f6f48ac723cecfc4b767299a5e25c0641679fbd2d4d20e9ffd5b9f0dab8"
|
||||
|
||||
### sm3-009
|
||||
- **来源**: GB/T 32918.4-2016 A.3 Example 2
|
||||
- **输入**: "0083E628CF701EE3141E8873FE55936ADF24963F5DC9C6480566C80F8A1D8CC51B656E6372797074696F6E207374616E6461726401524C647F0C0412DEFD468BDA3AE0E5A80FCC8F5C990FEE11602929232DCD9F36"
|
||||
- **预期输出**: "73a48625d3758fa37b3eab80e9cfcaba665e3199ea15a1fa8189d96f579125e4"
|
||||
27
docs/sm3hmac-testcases.md
Normal file
27
docs/sm3hmac-testcases.md
Normal file
@ -0,0 +1,27 @@
|
||||
# SM3 HMAC 测试用例
|
||||
|
||||
## 测试用例列表
|
||||
|
||||
### sm3hmac-001
|
||||
- **输入**:
|
||||
- 密钥: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"
|
||||
- 消息: "6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f70716162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071" ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopqabcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 的 hex 表示)
|
||||
- **预期输出**: "ca05e144ed05d1857840d1f318a4a8669e559fc8391f414485bfdf7bb408963a"
|
||||
|
||||
### sm3hmac-002
|
||||
- **输入**:
|
||||
- 密钥: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425"
|
||||
- 消息: "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
|
||||
- **预期输出**: "220bf579ded555393f0159f66c99877822a3ecf610d1552154b41d44b94db3ae"
|
||||
|
||||
### sm3hmac-003
|
||||
- **输入**:
|
||||
- 密钥: "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
|
||||
- 消息: "4869205468657265" ("Hi There" 的 hex 表示)
|
||||
- **预期输出**: "c0ba18c68b90c88bc07de794bfc7d2c8d19ec31ed8773bc2b390c9604e0be11e"
|
||||
|
||||
### sm3hmac-004
|
||||
- **输入**:
|
||||
- 密钥: "4a656665" ("Jefe" 的 hex 表示)
|
||||
- 消息: "7768617420646f2079612077616e7420666f72206e6f7468696e673f" ("what do ya want for nothing?" 的 hex 表示)
|
||||
- **预期输出**: "2e87f1d16862e6d964b50a5200bf2b10b764faa9680a296a2405f24bec39f882"
|
||||
57
docs/testcase.md
Normal file
57
docs/testcase.md
Normal file
@ -0,0 +1,57 @@
|
||||
\[
|
||||
{
|
||||
input: 'abc',
|
||||
hash: '66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0'
|
||||
},
|
||||
{
|
||||
input: 'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd',
|
||||
hash: 'debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732'
|
||||
},
|
||||
{
|
||||
input:
|
||||
'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd',
|
||||
hash: '6888fa292df4b51341e82e3072fbdd63598439c64eda318a81756ca71a7a6c15'
|
||||
},
|
||||
{
|
||||
// From \[GBT.32918.2-2016] A.2 Example 1
|
||||
input: sjcl.codec.hex.toBits(
|
||||
'0090414C494345313233405941484F4F2E434F4D787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E49863E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A20AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857'
|
||||
),
|
||||
hash: 'f4a38489e32b45b6f876e3ac2168ca392362dc8f23459c1d1146fc3dbfb7bc9a'
|
||||
},
|
||||
{
|
||||
// From \[GBT.32918.2-2016] A.2 Example 2
|
||||
input: sjcl.codec.hex.toBits(
|
||||
'F4A38489E32B45B6F876E3AC2168CA392362DC8F23459C1D1146FC3DBFB7BC9A6D65737361676520646967657374'
|
||||
),
|
||||
hash: 'b524f552cd82b8b028476e005c377fb19a87e6fc682d48bb5d42e3d9b9effe76'
|
||||
},
|
||||
{
|
||||
// GB/T 32918.2-2016 A.3 Example 1
|
||||
input: sjcl.codec.hex.toBits(
|
||||
'0090414C494345313233405941484F4F2E434F4D00000000000000000000000000000000000000000000000000000000000000000000E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E0165961645281A8626607B917F657D7E9382F1EA5CD931F40F6627F357542653B201686522130D590FB8DE635D8FCA715CC6BF3D05BEF3F75DA5D543454448166612'
|
||||
),
|
||||
hash: '26352af82ec19f207bbc6f9474e11e90ce0f7ddace03b27f801817e897a81fd5'
|
||||
},
|
||||
{
|
||||
// From \[GBT.32918.2-2016] A.3 Example 2
|
||||
input: sjcl.codec.hex.toBits(
|
||||
'26352AF82EC19F207BBC6F9474E11E90CE0F7DDACE03B27F801817E897A81FD56D65737361676520646967657374'
|
||||
),
|
||||
hash: 'ad673cbda311417129a9eaa5f9ab1aa1633ad47718a84dfd46c17c6fa0aa3b12'
|
||||
},
|
||||
{
|
||||
// GB/T 32918.4-2016 A.3 Example 1
|
||||
input: sjcl.codec.hex.toBits(
|
||||
'01C6271B31F6BE396A4166C0616CF4A8ACDA5BEF4DCBF2DD42656E6372797074696F6E207374616E646172640147AF35DFA1BFE2F161521BCF59BAB83564868D9295881735'
|
||||
),
|
||||
hash: 'f0a41f6f48ac723cecfc4b767299a5e25c0641679fbd2d4d20e9ffd5b9f0dab8'
|
||||
},
|
||||
{
|
||||
// GB/T 32918.4-2016 A.3 Example 2
|
||||
input: sjcl.codec.hex.toBits(
|
||||
'0083E628CF701EE3141E8873FE55936ADF24963F5DC9C6480566C80F8A1D8CC51B656E6372797074696F6E207374616E6461726401524C647F0C0412DEFD468BDA3AE0E5A80FCC8F5C990FEE11602929232DCD9F36'
|
||||
),
|
||||
hash: '73a48625d3758fa37b3eab80e9cfcaba665e3199ea15a1fa8189d96f579125e4'
|
||||
}
|
||||
]
|
||||
20
src/App.tsx
20
src/App.tsx
@ -25,6 +25,7 @@ function App() {
|
||||
const [sm4Iv, setSm4Iv] = useState('')
|
||||
const [sm4Message, setSm4Message] = useState('')
|
||||
const [sm4Mode, setSm4Mode] = useState('ecb')
|
||||
const [sm4PaddingMode, setSm4PaddingMode] = useState<'pkcs7' | 'none'>('pkcs7')
|
||||
const [sm4Encrypted, setSm4Encrypted] = useState('')
|
||||
const [sm4Decrypted, setSm4Decrypted] = useState('')
|
||||
|
||||
@ -116,7 +117,7 @@ function App() {
|
||||
// SM4 加密
|
||||
const handleEncryptSm4 = () => {
|
||||
try {
|
||||
const encrypted = sm4Encrypt(sm4Message, sm4Key, sm4Mode, sm4Iv)
|
||||
const encrypted = sm4Encrypt(sm4Message, sm4Key, sm4Mode, sm4Iv, sm4PaddingMode)
|
||||
setSm4Encrypted(encrypted)
|
||||
} catch (error) {
|
||||
alert('加密失败: ' + (error instanceof Error ? error.message : error))
|
||||
@ -126,7 +127,7 @@ function App() {
|
||||
// SM4 解密
|
||||
const handleDecryptSm4 = () => {
|
||||
try {
|
||||
const decrypted = sm4Decrypt(sm4Encrypted, sm4Key, sm4Mode, sm4Iv)
|
||||
const decrypted = sm4Decrypt(sm4Encrypted, sm4Key, sm4Mode, sm4Iv, sm4PaddingMode)
|
||||
setSm4Decrypted(decrypted)
|
||||
} catch (error) {
|
||||
alert('解密失败: ' + (error instanceof Error ? error.message : error))
|
||||
@ -347,6 +348,21 @@ function App() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label>填充模式</label>
|
||||
<div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
|
||||
{(['pkcs7', 'none'] as const).map(paddingMode => (
|
||||
<button
|
||||
key={paddingMode}
|
||||
className={sm4PaddingMode === paddingMode ? 'primary' : ''}
|
||||
onClick={() => setSm4PaddingMode(paddingMode)}
|
||||
>
|
||||
{paddingMode}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label>消息</label>
|
||||
<textarea
|
||||
|
||||
22
src/__tests__/algorithm/sm4-gcm.test.ts
Normal file
22
src/__tests__/algorithm/sm4-gcm.test.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { sm4Encrypt, sm4Decrypt } from '../../utils/algorithm/sm4'
|
||||
|
||||
describe('SM4 GCM 模式测试(用户提供的测试用例)', () => {
|
||||
test('用户提供的 GCM 测试用例', () => {
|
||||
const key = '00000000000000000000000000000000'
|
||||
const iv = '000000000000000000000000'
|
||||
const message = '00000000000000000000000000000000'
|
||||
const expected = '7de2aa7f1110188218063be1bfeb6d89b851b5f39493752be508f1bb4482c557'
|
||||
|
||||
const encrypted = sm4Encrypt(message, key, 'gcm', iv, 'none')
|
||||
console.log('实际结果:', encrypted)
|
||||
console.log('预期结果:', expected)
|
||||
console.log('结果是否匹配:', encrypted.toUpperCase() === expected.toUpperCase())
|
||||
|
||||
// 验证加密结果
|
||||
expect(encrypted.toUpperCase()).toBe(expected.toUpperCase())
|
||||
|
||||
// 验证解密结果
|
||||
const decrypted = sm4Decrypt(encrypted, key, 'gcm', iv, 'none')
|
||||
expect(decrypted.toUpperCase()).toBe(message.toUpperCase())
|
||||
})
|
||||
})
|
||||
@ -139,3 +139,4 @@ describe('SM4 算法测试', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -5,14 +5,33 @@ 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 => {
|
||||
// 验证消息是否为有效的 hex 字符串
|
||||
if (!isValidHex(message)) {
|
||||
throw new Error('Invalid message: must be hex string')
|
||||
try {
|
||||
// 验证消息是否为有效的 hex 字符串
|
||||
if (!isValidHex(message)) {
|
||||
throw new Error('Invalid message: must be hex string')
|
||||
}
|
||||
|
||||
console.log('Input hex message:', message)
|
||||
|
||||
// 直接使用 hex 字符串计算 SM3
|
||||
const result = SM3.digest(message, 'hex')
|
||||
console.log('SM3 result:', result)
|
||||
|
||||
// 处理返回结果
|
||||
const hexResult = typeof result === 'string' ? result : arrayBufferToHex(result)
|
||||
console.log('Hex result:', hexResult)
|
||||
|
||||
return hexResult
|
||||
} catch (error) {
|
||||
console.error('SM3 digest error:', error)
|
||||
throw error
|
||||
}
|
||||
|
||||
// 直接使用 message 作为输入,gm-crypto 会自动处理
|
||||
const result = SM3.digest(message)
|
||||
return typeof result === 'string' ? result : Buffer.from(result).toString('hex')
|
||||
}
|
||||
|
||||
@ -122,18 +122,19 @@ export const sm4Encrypt = (message: string, key: string, mode: string, iv?: stri
|
||||
const ivBytes = hexToBytes(iv)
|
||||
const ivBits = sjcl.codec.bytes.toBits(ivBytes)
|
||||
const dataBits = sjcl.codec.bytes.toBits(dataToEncrypt)
|
||||
const encryptedResult = sjcl.mode.gcm.encrypt(sm4Key, dataBits, ivBits, sjcl.codec.bytes.toBits([]))
|
||||
// GCM 模式返回的数据包含 tag,需要分离
|
||||
// 传递标签长度参数(128 位)
|
||||
const encryptedResult = sjcl.mode.gcm.encrypt(sm4Key, dataBits, ivBits, sjcl.codec.bytes.toBits([]), 128)
|
||||
// GCM 模式返回的数据包含 tag
|
||||
if (!encryptedResult) {
|
||||
throw new Error('GCM encryption failed: result is undefined')
|
||||
}
|
||||
// 检查 encryptedResult 的类型
|
||||
if (Array.isArray(encryptedResult)) {
|
||||
// 如果返回的是数组,直接使用
|
||||
// 如果返回的是数组,直接使用(包含了 tag)
|
||||
const encryptedBytes = sjcl.codec.bytes.fromBits(encryptedResult)
|
||||
return bytesToHex(encryptedBytes)
|
||||
} else if (encryptedResult.data) {
|
||||
// 如果返回的是对象,使用 data 属性
|
||||
// 如果返回的是对象,使用 data 属性(可能已经包含了 tag)
|
||||
const encryptedBits = encryptedResult.data
|
||||
const encryptedBytes = sjcl.codec.bytes.fromBits(encryptedBits)
|
||||
return bytesToHex(encryptedBytes)
|
||||
@ -208,7 +209,8 @@ export const sm4Decrypt = (encrypted: string, key: string, mode: string, iv?: st
|
||||
const ivBytes = hexToBytes(iv)
|
||||
const ivBits = sjcl.codec.bytes.toBits(ivBytes)
|
||||
const encryptedBits = sjcl.codec.bytes.toBits(encryptedBytes)
|
||||
const decryptedResult = sjcl.mode.gcm.decrypt(sm4Key, encryptedBits, ivBits, sjcl.codec.bytes.toBits([]))
|
||||
// 传递标签长度参数(128 位)
|
||||
const decryptedResult = sjcl.mode.gcm.decrypt(sm4Key, encryptedBits, ivBits, sjcl.codec.bytes.toBits([]), 128)
|
||||
// 检查 decryptedResult 的类型
|
||||
if (!decryptedResult) {
|
||||
throw new Error('GCM decryption failed: result is undefined')
|
||||
|
||||
21
test-gcm.js
Normal file
21
test-gcm.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { sm4Encrypt } from './src/utils/algorithm/sm4.ts';
|
||||
|
||||
// 用户提供的测试用例
|
||||
const key = '00000000000000000000000000000000';
|
||||
const iv = '000000000000000000000000';
|
||||
const message = '00000000000000000000000000000000';
|
||||
const expected = '7de2aa7f1110188218063be1bfeb6d89b851b5f39493752be508f1bb4482c557';
|
||||
|
||||
console.log('测试 SM4 GCM 模式...');
|
||||
console.log('密钥:', key);
|
||||
console.log('IV:', iv);
|
||||
console.log('消息:', message);
|
||||
console.log('预期结果:', expected);
|
||||
|
||||
try {
|
||||
const result = sm4Encrypt(message, key, 'gcm', iv, 'none');
|
||||
console.log('实际结果:', result);
|
||||
console.log('结果是否匹配:', result.toUpperCase() === expected.toUpperCase());
|
||||
} catch (error) {
|
||||
console.error('错误:', error.message);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user