feat(crypto): 新增 RSA 验签工具
This commit is contained in:
@@ -4,3 +4,4 @@ export { hkdfSha256 } from './hkdf'
|
|||||||
export { hmacSha256, hmacSha256Base64 } from './hmac'
|
export { hmacSha256, hmacSha256Base64 } from './hmac'
|
||||||
export { generatePgpKeyPair, pgpSignDetached, pgpVerifyDetached, validatePgpPrivateKey } from './pgp'
|
export { generatePgpKeyPair, pgpSignDetached, pgpVerifyDetached, validatePgpPrivateKey } from './pgp'
|
||||||
export { rsaOaepEncrypt } from './rsa-oaep'
|
export { rsaOaepEncrypt } from './rsa-oaep'
|
||||||
|
export { rsaVerifySignature, validateRsaPublicKey } from './rsa-signature'
|
||||||
|
|||||||
24
packages/crypto/src/rsa-signature.test.ts
Normal file
24
packages/crypto/src/rsa-signature.test.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { describe, expect, it } from 'bun:test'
|
||||||
|
import { constants, createSign, generateKeyPairSync } from 'node:crypto'
|
||||||
|
import { rsaVerifySignature, validateRsaPublicKey } from './rsa-signature'
|
||||||
|
|
||||||
|
describe('rsaVerifySignature', () => {
|
||||||
|
it('verifies SHA256withRSA signatures over raw payload bytes', () => {
|
||||||
|
const { privateKey, publicKey } = generateKeyPairSync('rsa', { modulusLength: 2048 })
|
||||||
|
const payload = Buffer.from('eyJsaWNlbmNlX2lkIjoiTElDLTAwMSIsImV4cGlyZV90aW1lIjoiMjAyNy0wMy0xOSJ9', 'utf-8')
|
||||||
|
|
||||||
|
const signer = createSign('RSA-SHA256')
|
||||||
|
signer.update(payload)
|
||||||
|
signer.end()
|
||||||
|
|
||||||
|
const signature = signer.sign({ key: privateKey, padding: constants.RSA_PKCS1_PADDING })
|
||||||
|
const publicKeyBase64 = publicKey.export({ format: 'der', type: 'spki' }).toString('base64')
|
||||||
|
|
||||||
|
expect(rsaVerifySignature(payload, signature, publicKeyBase64)).toBe(true)
|
||||||
|
expect(rsaVerifySignature(Buffer.from(`${payload}x`, 'utf-8'), signature, publicKeyBase64)).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('rejects malformed SPKI public keys', () => {
|
||||||
|
expect(() => validateRsaPublicKey('not-a-public-key')).toThrow()
|
||||||
|
})
|
||||||
|
})
|
||||||
19
packages/crypto/src/rsa-signature.ts
Normal file
19
packages/crypto/src/rsa-signature.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { constants, createPublicKey, verify } from 'node:crypto'
|
||||||
|
|
||||||
|
const createSpkiPublicKey = (publicKeyBase64: string) => {
|
||||||
|
return createPublicKey({
|
||||||
|
key: Buffer.from(publicKeyBase64, 'base64'),
|
||||||
|
format: 'der',
|
||||||
|
type: 'spki',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateRsaPublicKey = (publicKeyBase64: string): void => {
|
||||||
|
createSpkiPublicKey(publicKeyBase64)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const rsaVerifySignature = (data: Uint8Array, signature: Uint8Array, publicKeyBase64: string): boolean => {
|
||||||
|
const publicKey = createSpkiPublicKey(publicKeyBase64)
|
||||||
|
|
||||||
|
return verify('RSA-SHA256', data, { key: publicKey, padding: constants.RSA_PKCS1_PADDING }, signature)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user