sm2 改进

This commit is contained in:
cheney 2026-04-18 14:58:39 +08:00
parent c9d66a77b1
commit 20c27b2e5b
4 changed files with 239 additions and 168 deletions

View File

@ -59,8 +59,10 @@ function App() {
const [sm2Message, setSm2Message] = useState('') const [sm2Message, setSm2Message] = useState('')
const [sm2Encrypted, setSm2Encrypted] = useState('') const [sm2Encrypted, setSm2Encrypted] = useState('')
const [sm2Decrypted, setSm2Decrypted] = useState('') const [sm2Decrypted, setSm2Decrypted] = useState('')
const [sm2SignMessage, setSm2SignMessage] = useState('')
const [sm2Signature, setSm2Signature] = useState('') const [sm2Signature, setSm2Signature] = useState('')
const [sm2VerifyResult, setSm2VerifyResult] = useState('') const [sm2VerifyResult, setSm2VerifyResult] = useState('')
const [sm2ActiveTab, setSm2ActiveTab] = useState('encrypt')
// 转换工具状态 // 转换工具状态
const [hexInput, setHexInput] = useState('') const [hexInput, setHexInput] = useState('')
@ -172,8 +174,8 @@ function App() {
// SM2 签名 // SM2 签名
const handleSignSm2 = () => { const handleSignSm2 = () => {
try { try {
console.log('开始签名,消息:', sm2Message, '私钥:', sm2PrivateKey) console.log('开始签名,消息:', sm2SignMessage, '私钥:', sm2PrivateKey)
const signature = sm2Sign(sm2Message, sm2PrivateKey) const signature = sm2Sign(sm2SignMessage, sm2PrivateKey)
console.log('签名成功,结果:', signature) console.log('签名成功,结果:', signature)
setSm2Signature(signature) setSm2Signature(signature)
} catch (error) { } catch (error) {
@ -185,8 +187,8 @@ function App() {
// SM2 验证签名 // SM2 验证签名
const handleVerifySm2 = () => { const handleVerifySm2 = () => {
try { try {
console.log('开始验签,消息:', sm2Message, '签名:', sm2Signature, '公钥:', sm2PublicKey) console.log('开始验签,消息:', sm2SignMessage, '签名:', sm2Signature, '公钥:', sm2PublicKey)
const result = sm2Verify(sm2Message, sm2Signature, sm2PublicKey) const result = sm2Verify(sm2SignMessage, sm2Signature, sm2PublicKey)
console.log('验签成功,结果:', result) console.log('验签成功,结果:', result)
setSm2VerifyResult(result ? '验证成功' : '验证失败') setSm2VerifyResult(result ? '验证成功' : '验证失败')
} catch (error) { } catch (error) {
@ -382,8 +384,8 @@ function App() {
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label> <label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<textarea <textarea
value={sm2PublicKey} value={sm2PublicKey}
readOnly onChange={(e) => setSm2PublicKey(e.target.value)}
placeholder="公钥将显示在这里" placeholder="输入公钥 (hex) 或点击生成密钥对"
style={{ style={{
width: '100%', width: '100%',
padding: '10px', padding: '10px',
@ -399,181 +401,246 @@ function App() {
</div> </div>
</div> </div>
{/* 加密/解密 */} {/* SM2 功能选项卡 */}
<div style={{ marginBottom: '20px', padding: '15px', backgroundColor: '#2d2d2d', borderRadius: '8px' }}> <div style={{ marginBottom: '20px' }}>
<h3 style={{ color: '#e0e0e0', marginBottom: '10px' }}>/</h3> <div style={{ display: 'flex', borderBottom: '1px solid #333', marginBottom: '20px', backgroundColor: '#2d2d2d', borderRadius: '8px 8px 0 0', overflow: 'hidden' }}>
<div className="form-group" style={{ marginBottom: '10px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<textarea
value={sm2Message}
onChange={(e) => setSm2Message(e.target.value)}
placeholder="输入要加密的消息 (hex)"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#3d3d3d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical',
minHeight: '100px'
}}
/>
</div>
<div className="form-group" style={{ marginBottom: '10px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<textarea
value={sm2Encrypted}
onChange={(e) => setSm2Encrypted(e.target.value)}
placeholder="输入加密结果 (hex)"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#3d3d3d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical',
minHeight: '100px'
}}
/>
</div>
<div className="form-group" style={{ marginBottom: '10px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<textarea
value={sm2Decrypted}
readOnly
placeholder="解密结果将显示在这里"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#3d3d3d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical',
minHeight: '100px'
}}
/>
</div>
<div className="button-group" style={{ display: 'flex', gap: '10px' }}>
<button <button
onClick={handleEncryptSm2} className={`tab ${sm2ActiveTab === 'encrypt' ? 'active' : ''}`}
onClick={() => setSm2ActiveTab('encrypt')}
style={{ style={{
padding: '10px 20px', padding: '12px 24px',
border: 'none', border: 'none',
borderRadius: '4px', background: sm2ActiveTab === 'encrypt' ? '#333' : '#2d2d2d',
background: '#f59e0b',
color: '#121212',
fontSize: '16px',
fontWeight: 'bold',
cursor: 'pointer', cursor: 'pointer',
transition: 'background 0.3s ease', fontSize: '16px',
flex: 1 fontWeight: sm2ActiveTab === 'encrypt' ? 'bold' : 'normal',
color: sm2ActiveTab === 'encrypt' ? '#f59e0b' : '#e0e0e0',
outline: 'none',
transition: 'all 0.3s ease',
borderBottom: sm2ActiveTab === 'encrypt' ? '3px solid #f59e0b' : 'none'
}} }}
> >
/
</button> </button>
<button <button
onClick={handleDecryptSm2} className={`tab ${sm2ActiveTab === 'sign' ? 'active' : ''}`}
onClick={() => setSm2ActiveTab('sign')}
style={{ style={{
padding: '10px 20px', padding: '12px 24px',
border: 'none', border: 'none',
borderRadius: '4px', background: sm2ActiveTab === 'sign' ? '#333' : '#2d2d2d',
background: '#f59e0b',
color: '#121212',
fontSize: '16px',
fontWeight: 'bold',
cursor: 'pointer', cursor: 'pointer',
transition: 'background 0.3s ease', fontSize: '16px',
flex: 1 fontWeight: sm2ActiveTab === 'sign' ? 'bold' : 'normal',
color: sm2ActiveTab === 'sign' ? '#f59e0b' : '#e0e0e0',
outline: 'none',
transition: 'all 0.3s ease',
borderBottom: sm2ActiveTab === 'sign' ? '3px solid #f59e0b' : 'none'
}} }}
> >
/
</button> </button>
</div> </div>
</div>
{/* 加密/解密 */}
{/* 签名/验证 */} {sm2ActiveTab === 'encrypt' && (
<div style={{ marginBottom: '20px', padding: '15px', backgroundColor: '#2d2d2d', borderRadius: '8px' }}> <div style={{ padding: '15px', backgroundColor: '#2d2d2d', borderRadius: '8px' }}>
<h3 style={{ color: '#e0e0e0', marginBottom: '10px' }}>/</h3> <h3 style={{ color: '#e0e0e0', marginBottom: '10px' }}>/</h3>
<div className="form-group" style={{ marginBottom: '10px' }}> <div className="form-group" style={{ marginBottom: '10px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label> <label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<textarea <textarea
value={sm2Signature} value={sm2Message}
onChange={(e) => setSm2Signature(e.target.value)} onChange={(e) => setSm2Message(e.target.value)}
placeholder="输入签名 (hex)" placeholder="输入要加密的消息 (hex)"
style={{ style={{
width: '100%', width: '100%',
padding: '10px', padding: '10px',
border: '1px solid #333', border: '1px solid #333',
borderRadius: '4px', borderRadius: '4px',
backgroundColor: '#3d3d3d', backgroundColor: '#3d3d3d',
color: '#e0e0e0', color: '#e0e0e0',
fontSize: '14px', fontSize: '14px',
resize: 'vertical', resize: 'vertical',
minHeight: '100px' minHeight: '100px'
}} }}
/> />
</div> </div>
<div className="form-group" style={{ marginBottom: '10px' }}> <div className="form-group" style={{ marginBottom: '10px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label> <label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<div <textarea
style={{ value={sm2Encrypted}
width: '100%', onChange={(e) => setSm2Encrypted(e.target.value)}
padding: '10px', placeholder="输入加密结果 (hex)"
border: '1px solid #333', style={{
borderRadius: '4px', width: '100%',
backgroundColor: '#3d3d3d', padding: '10px',
color: sm2VerifyResult === '验证成功' ? '#4ade80' : sm2VerifyResult === '验证失败' ? '#f87171' : '#e0e0e0', border: '1px solid #333',
fontSize: '14px', borderRadius: '4px',
minHeight: '40px', backgroundColor: '#3d3d3d',
display: 'flex', color: '#e0e0e0',
alignItems: 'center' fontSize: '14px',
}} resize: 'vertical',
> minHeight: '100px'
{sm2VerifyResult || '验证结果将显示在这里'} }}
/>
</div>
<div className="form-group" style={{ marginBottom: '10px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<textarea
value={sm2Decrypted}
readOnly
placeholder="解密结果将显示在这里"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#3d3d3d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical',
minHeight: '100px'
}}
/>
</div>
<div className="button-group" style={{ display: 'flex', gap: '10px' }}>
<button
onClick={handleEncryptSm2}
style={{
padding: '10px 20px',
border: 'none',
borderRadius: '4px',
background: '#f59e0b',
color: '#121212',
fontSize: '16px',
fontWeight: 'bold',
cursor: 'pointer',
transition: 'background 0.3s ease',
flex: 1
}}
>
</button>
<button
onClick={handleDecryptSm2}
style={{
padding: '10px 20px',
border: 'none',
borderRadius: '4px',
background: '#f59e0b',
color: '#121212',
fontSize: '16px',
fontWeight: 'bold',
cursor: 'pointer',
transition: 'background 0.3s ease',
flex: 1
}}
>
</button>
</div>
</div> </div>
</div> )}
<div className="button-group" style={{ display: 'flex', gap: '10px' }}>
<button {/* 签名/验证 */}
onClick={handleSignSm2} {sm2ActiveTab === 'sign' && (
style={{ <div style={{ padding: '15px', backgroundColor: '#2d2d2d', borderRadius: '8px' }}>
padding: '10px 20px', <h3 style={{ color: '#e0e0e0', marginBottom: '10px' }}>/</h3>
border: 'none', <div className="form-group" style={{ marginBottom: '10px' }}>
borderRadius: '4px', <label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
background: '#f59e0b', <textarea
color: '#121212', value={sm2SignMessage}
fontSize: '16px', onChange={(e) => setSm2SignMessage(e.target.value)}
fontWeight: 'bold', placeholder="输入要签名的消息 (hex)"
cursor: 'pointer', style={{
transition: 'background 0.3s ease', width: '100%',
flex: 1 padding: '10px',
}} border: '1px solid #333',
> borderRadius: '4px',
backgroundColor: '#3d3d3d',
</button> color: '#e0e0e0',
<button fontSize: '14px',
onClick={handleVerifySm2} resize: 'vertical',
style={{ minHeight: '100px'
padding: '10px 20px', }}
border: 'none', />
borderRadius: '4px', </div>
background: '#f59e0b', <div className="form-group" style={{ marginBottom: '10px' }}>
color: '#121212', <label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
fontSize: '16px', <textarea
fontWeight: 'bold', value={sm2Signature}
cursor: 'pointer', onChange={(e) => setSm2Signature(e.target.value)}
transition: 'background 0.3s ease', placeholder="输入签名 (hex)"
flex: 1 style={{
}} width: '100%',
> padding: '10px',
border: '1px solid #333',
</button> borderRadius: '4px',
</div> backgroundColor: '#3d3d3d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical',
minHeight: '100px'
}}
/>
</div>
<div className="form-group" style={{ marginBottom: '10px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<div
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#3d3d3d',
color: sm2VerifyResult === '验证成功' ? '#4ade80' : sm2VerifyResult === '验证失败' ? '#f87171' : '#e0e0e0',
fontSize: '14px',
minHeight: '40px',
display: 'flex',
alignItems: 'center'
}}
>
{sm2VerifyResult || '验证结果将显示在这里'}
</div>
</div>
<div className="button-group" style={{ display: 'flex', gap: '10px' }}>
<button
onClick={handleSignSm2}
style={{
padding: '10px 20px',
border: 'none',
borderRadius: '4px',
background: '#f59e0b',
color: '#121212',
fontSize: '16px',
fontWeight: 'bold',
cursor: 'pointer',
transition: 'background 0.3s ease',
flex: 1
}}
>
</button>
<button
onClick={handleVerifySm2}
style={{
padding: '10px 20px',
border: 'none',
borderRadius: '4px',
background: '#f59e0b',
color: '#121212',
fontSize: '16px',
fontWeight: 'bold',
cursor: 'pointer',
transition: 'background 0.3s ease',
flex: 1
}}
>
</button>
</div>
</div>
)}
</div> </div>
</div> </div>
)} )}

View File

@ -10,6 +10,7 @@ declare module 'sm-crypto' {
doDecrypt: (ciphertext: string, privateKey: string) => string; doDecrypt: (ciphertext: string, privateKey: string) => string;
doSignature: (message: string | Uint8Array, privateKey: string, options?: { hash?: boolean, der?: boolean, userId?: string, publicKey?: string, pointPool?: any[] }) => string; doSignature: (message: string | Uint8Array, privateKey: string, options?: { hash?: boolean, der?: boolean, userId?: string, publicKey?: string, pointPool?: any[] }) => string;
doVerifySignature: (message: string | Uint8Array, signature: string, publicKey: string, options?: { hash?: boolean, der?: boolean, userId?: string }) => boolean; doVerifySignature: (message: string | Uint8Array, signature: string, publicKey: string, options?: { hash?: boolean, der?: boolean, userId?: string }) => boolean;
getPublicKeyFromPrivateKey: (privateKey: string) => string;
}; };
export const sm3: { export const sm3: {

View File

@ -15,12 +15,15 @@ export const sm2GenerateKeyPair = (): { privateKey: string; publicKey: string }
// SM2 从私钥计算公钥 // SM2 从私钥计算公钥
export const sm2GetPublicKeyFromPrivateKey = (privateKey: string): string => { export const sm2GetPublicKeyFromPrivateKey = (privateKey: string): string => {
// 验证私钥是否为有效的 hex 字符串 // 验证私钥是否为有效的 hex 字符串
if (!privateKey) {
throw new Error('Private key is required')
}
if (!isValidHex(privateKey)) { if (!isValidHex(privateKey)) {
throw new Error('Invalid private key: must be hex string') throw new Error('Invalid private key: must be hex string')
} }
const keypair = sm2.generateKeyPairHex(privateKey) const publicKey = sm2.getPublicKeyFromPrivateKey(privateKey)
return keypair.publicKey return publicKey
} }
// SM2 加密 // SM2 加密

View File

@ -1 +1 @@
export const VERSION = "V1.0-20260418053331"; export const VERSION = "V1.0-20260418065443";