web 端 sm4 验证正确

This commit is contained in:
cheney 2026-04-15 17:34:25 +08:00
parent ffd4d17f5d
commit fe1f7c14b4
5 changed files with 69 additions and 7 deletions

View File

@ -25,6 +25,7 @@ function App() {
const [sm4Iv, setSm4Iv] = useState('') const [sm4Iv, setSm4Iv] = useState('')
const [sm4Message, setSm4Message] = useState('') const [sm4Message, setSm4Message] = useState('')
const [sm4Mode, setSm4Mode] = useState('ecb') const [sm4Mode, setSm4Mode] = useState('ecb')
const [sm4PaddingMode, setSm4PaddingMode] = useState<'pkcs7' | 'none'>('pkcs7')
const [sm4Encrypted, setSm4Encrypted] = useState('') const [sm4Encrypted, setSm4Encrypted] = useState('')
const [sm4Decrypted, setSm4Decrypted] = useState('') const [sm4Decrypted, setSm4Decrypted] = useState('')
@ -116,7 +117,7 @@ function App() {
// SM4 加密 // SM4 加密
const handleEncryptSm4 = () => { const handleEncryptSm4 = () => {
try { try {
const encrypted = sm4Encrypt(sm4Message, sm4Key, sm4Mode, sm4Iv) const encrypted = sm4Encrypt(sm4Message, sm4Key, sm4Mode, sm4Iv, sm4PaddingMode)
setSm4Encrypted(encrypted) setSm4Encrypted(encrypted)
} catch (error) { } catch (error) {
alert('加密失败: ' + (error instanceof Error ? error.message : error)) alert('加密失败: ' + (error instanceof Error ? error.message : error))
@ -126,7 +127,7 @@ function App() {
// SM4 解密 // SM4 解密
const handleDecryptSm4 = () => { const handleDecryptSm4 = () => {
try { try {
const decrypted = sm4Decrypt(sm4Encrypted, sm4Key, sm4Mode, sm4Iv) const decrypted = sm4Decrypt(sm4Encrypted, sm4Key, sm4Mode, sm4Iv, sm4PaddingMode)
setSm4Decrypted(decrypted) setSm4Decrypted(decrypted)
} catch (error) { } catch (error) {
alert('解密失败: ' + (error instanceof Error ? error.message : error)) alert('解密失败: ' + (error instanceof Error ? error.message : error))
@ -347,6 +348,21 @@ function App() {
</div> </div>
</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"> <div className="form-group">
<label></label> <label></label>
<textarea <textarea

View 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())
})
})

View File

@ -139,3 +139,4 @@ describe('SM4 算法测试', () => {
} }
}) })
}) })

View File

@ -122,18 +122,19 @@ export const sm4Encrypt = (message: string, key: string, mode: string, iv?: stri
const ivBytes = hexToBytes(iv) const ivBytes = hexToBytes(iv)
const ivBits = sjcl.codec.bytes.toBits(ivBytes) const ivBits = sjcl.codec.bytes.toBits(ivBytes)
const dataBits = sjcl.codec.bytes.toBits(dataToEncrypt) const dataBits = sjcl.codec.bytes.toBits(dataToEncrypt)
const encryptedResult = sjcl.mode.gcm.encrypt(sm4Key, dataBits, ivBits, sjcl.codec.bytes.toBits([])) // 传递标签长度参数128 位)
// GCM 模式返回的数据包含 tag需要分离 const encryptedResult = sjcl.mode.gcm.encrypt(sm4Key, dataBits, ivBits, sjcl.codec.bytes.toBits([]), 128)
// GCM 模式返回的数据包含 tag
if (!encryptedResult) { if (!encryptedResult) {
throw new Error('GCM encryption failed: result is undefined') throw new Error('GCM encryption failed: result is undefined')
} }
// 检查 encryptedResult 的类型 // 检查 encryptedResult 的类型
if (Array.isArray(encryptedResult)) { if (Array.isArray(encryptedResult)) {
// 如果返回的是数组,直接使用 // 如果返回的是数组,直接使用(包含了 tag
const encryptedBytes = sjcl.codec.bytes.fromBits(encryptedResult) const encryptedBytes = sjcl.codec.bytes.fromBits(encryptedResult)
return bytesToHex(encryptedBytes) return bytesToHex(encryptedBytes)
} else if (encryptedResult.data) { } else if (encryptedResult.data) {
// 如果返回的是对象,使用 data 属性 // 如果返回的是对象,使用 data 属性(可能已经包含了 tag
const encryptedBits = encryptedResult.data const encryptedBits = encryptedResult.data
const encryptedBytes = sjcl.codec.bytes.fromBits(encryptedBits) const encryptedBytes = sjcl.codec.bytes.fromBits(encryptedBits)
return bytesToHex(encryptedBytes) return bytesToHex(encryptedBytes)
@ -208,7 +209,8 @@ export const sm4Decrypt = (encrypted: string, key: string, mode: string, iv?: st
const ivBytes = hexToBytes(iv) const ivBytes = hexToBytes(iv)
const ivBits = sjcl.codec.bytes.toBits(ivBytes) const ivBits = sjcl.codec.bytes.toBits(ivBytes)
const encryptedBits = sjcl.codec.bytes.toBits(encryptedBytes) 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 的类型 // 检查 decryptedResult 的类型
if (!decryptedResult) { if (!decryptedResult) {
throw new Error('GCM decryption failed: result is undefined') throw new Error('GCM decryption failed: result is undefined')

21
test-gcm.js Normal file
View 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);
}