Skip to content

Commit

Permalink
fix(sm2/kx): align key exchange with standard
Browse files Browse the repository at this point in the history
  • Loading branch information
Cubelrti committed Jun 28, 2023
1 parent 6753f47 commit b4fae83
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 18 deletions.
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
- ✔️ 通过全部历史单元测试,包括 SM2、SM3 和 SM4
- 🎲 自动选择最优的安全随机数实现,避免使用 `Math.random()``Date.now()` 进行模拟
- 📚 同时导出 ES Module 和 CommonJS 两种格式,可按需使用
- 🔑 新增密钥交换 API(实验性)
- 🔑 提供 SM2 密钥交换 API
- 🎒 未压缩大小 34kb,压缩后 17kb

## 安装
Expand Down Expand Up @@ -167,7 +167,7 @@ let decryptData = sm4.decrypt(encryptData, key, {padding: 'none', output: 'array
let decryptData = sm4.decrypt(encryptData, key, {mode: 'cbc', iv: 'fedcba98765432100123456789abcdef'}) // 解密,cbc 模式
```

### 密钥交换(实验性)
### 密钥交换

```js
import { sm2 } from 'sm-crypto-v2'
Expand All @@ -177,10 +177,17 @@ const keyPairB = sm2.generateKeyPairHex() // B 的秘钥对
const ephemeralKeypairA = sm2.generateKeyPairHex() // A 的临时秘钥对
const ephemeralKeypairB = sm2.generateKeyPairHex() // B 的临时秘钥对

// A 所需参数:A 的秘钥对,A 的临时秘钥对,B 的公钥,B 的临时秘钥公钥,AB 的身份ID,长度
const sharedKeyFromA = sm2.calculateSharedKey(keyPairA, ephemeralKeypairA, keyPairB.publicKey, ephemeralKeypairB.publicKey, 'alice@yahoo.com', 'bob@yahoo.com', 233)
// B 所需参数:B 的秘钥对,B 的临时秘钥对,A 的公钥,A 的临时秘钥公钥,AB 的身份ID,长度
const sharedKeyFromB = sm2.calculateSharedKey(keyPairB, ephemeralKeypairB, keyPairA.publicKey, ephemeralKeypairA.publicKey, 'alice@yahoo.com', 'bob@yahoo.com', 233)
// 无身份的密钥交换
// A 所需参数:A 的秘钥对,A 的临时秘钥对,B 的公钥,B 的临时秘钥公钥,长度,是否为接收方(默认为 false)
const sharedKeyFromA = sm2.calculateSharedKey(keyPairA, ephemeralKeypairA, keyPairB.publicKey, ephemeralKeypairB.publicKey, 233)
// B 所需参数:B 的秘钥对,B 的临时秘钥对,A 的公钥,A 的临时秘钥公钥,长度,是否为接收方(默认为 false)
const sharedKeyFromB = sm2.calculateSharedKey(keyPairB, ephemeralKeypairB, keyPairA.publicKey, ephemeralKeypairA.publicKey, 233, true)

// 带身份的密钥交换
// A 所需参数:A 的秘钥对,A 的临时秘钥对,B 的公钥,B 的临时秘钥公钥,长度,是否为接收方(默认为 false),A 的身份,B 的身份
const sharedKeyFromA = sm2.calculateSharedKey(keyPairA, ephemeralKeypairA, keyPairB.publicKey, ephemeralKeypairB.publicKey, 233, false, 'alice@yahoo.com', 'bob@yahoo.com')
// B 所需参数:B 的秘钥对,B 的临时秘钥对,A 的公钥,A 的临时秘钥公钥,长度,是否为接收方(默认为 false),B 的身份,A 的身份
const sharedKeyFromB = sm2.calculateSharedKey(keyPairB, ephemeralKeypairB, keyPairA.publicKey, ephemeralKeypairA.publicKey, 233, true, 'bob@yahoo.com', 'alice@yahoo.com')

// expect(sharedKeyFromA).toEqual(sharedKeyFromB) => true
```
Expand Down
13 changes: 9 additions & 4 deletions src/sm2/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,7 @@ export function doVerifySignature(msg: string | Uint8Array, signHex: string, pub
return r === R
}

/**
* sm3杂凑算法
*/
export function getHash(hashHex: string | Uint8Array, publicKey: string, userId = '1234567812345678') {
export function getZ(publicKey: string, userId = '1234567812345678') {
// z = hash(entl || userId || a || b || gx || gy || px || py)
userId = utf8ToHex(userId)
const a = leftPad(utils.numberToHexUnpadded(sm2Curve.CURVE.a), 64)
Expand Down Expand Up @@ -241,6 +238,14 @@ export function getHash(hashHex: string | Uint8Array, publicKey: string, userId

const z = sm3(utils.concatBytes(new Uint8Array([entl >> 8 & 0x00ff, entl & 0x00ff]), data))

return z
}

/**
* sm3杂凑算法
*/
export function getHash(hashHex: string | Uint8Array, publicKey: string, userId = '1234567812345678') {
const z = getZ(publicKey, userId)
// e = hash(z || msg)
return bytesToHex(sm3(utils.concatBytes(z, typeof hashHex === 'string' ? hexToArray(hashHex) : hashHex)))
}
Expand Down
15 changes: 9 additions & 6 deletions src/sm2/kx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { field, sm2Curve } from './ec';
import { KeyPair, hexToArray, leftPad } from './utils';
import * as utils from '@noble/curves/abstract/utils';
import { sm3 } from './sm3';
import { EmptyArray } from '.';
import { EmptyArray, getZ } from '.';


// 用到的常数
Expand Down Expand Up @@ -39,28 +39,31 @@ function hkdf(z: Uint8Array, keylen: number) {
return msg
}


export function calculateSharedKey(
keypairA: KeyPair,
ephemeralKeypairA: KeyPair,
publicKeyB: string,
ephemeralPublicKeyB: string,
sharedKeyLength: number,
isRecipient = false,
idA: string = '1234567812345678',
idB: string = '1234567812345678',
sharedKeyLength: number,
) {
const RA = sm2Curve.ProjectivePoint.fromHex(ephemeralKeypairA.publicKey)
const RB = sm2Curve.ProjectivePoint.fromHex(ephemeralPublicKeyB)
// const PA = sm2Curve.ProjectivePoint.fromHex(keypairA.publicKey) // 用不到
const PB = sm2Curve.ProjectivePoint.fromHex(publicKeyB)
const ZA = hexToArray(idA)
const ZB = hexToArray(idB)
let ZA = getZ(keypairA.publicKey, idA)
let ZB = getZ(publicKeyB, idB)
if (isRecipient) {
[ZA, ZB] = [ZB, ZA];
}
const rA = utils.hexToNumber(ephemeralKeypairA.privateKey)
const dA = utils.hexToNumber(keypairA.privateKey)
// 1.先算 tA
const x1 = RA.x
// x1_ = 2^w + (x1 & (2^w - 1))
const x1_ = field.add(wPow2, (x1 & wPow2Sub1))
const x1_ = wPow2 + (x1 & wPow2Sub1)
// tA = (dA + x1b * rA) mod n
const tA = field.add(dA, field.mulN(x1_, rA))

Expand Down
13 changes: 11 additions & 2 deletions test/kx.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,17 @@ describe('key exchange', () => {
const ephemeralKeypairA = sm2.generateKeyPairHex()
const ephemeralKeypairB = sm2.generateKeyPairHex()
it('agree a key', () => {
const sharedKeyFromA = sm2.calculateSharedKey(keyPairA, ephemeralKeypairA, keyPairB.publicKey, ephemeralKeypairB.publicKey, 'alice@yahoo.com', 'bob@yahoo.com', 233)
const sharedKeyFromB = sm2.calculateSharedKey(keyPairB, ephemeralKeypairB, keyPairA.publicKey, ephemeralKeypairA.publicKey, 'alice@yahoo.com', 'bob@yahoo.com', 233)
const sharedKeyFromA = sm2.calculateSharedKey(keyPairA, ephemeralKeypairA, keyPairB.publicKey, ephemeralKeypairB.publicKey, 233)
const sharedKeyFromB = sm2.calculateSharedKey(keyPairB, ephemeralKeypairB, keyPairA.publicKey, ephemeralKeypairA.publicKey, 233, true)
console.log({
sharedKeyFromA,
sharedKeyFromB,
})
expect(sharedKeyFromA).toEqual(sharedKeyFromB)
})
it('agree a key with user identity', () => {
const sharedKeyFromA = sm2.calculateSharedKey(keyPairA, ephemeralKeypairA, keyPairB.publicKey, ephemeralKeypairB.publicKey, 233, false, 'alice@yahoo.com', 'bob@yahoo.com')
const sharedKeyFromB = sm2.calculateSharedKey(keyPairB, ephemeralKeypairB, keyPairA.publicKey, ephemeralKeypairA.publicKey, 233, true, 'bob@yahoo.com', 'alice@yahoo.com')
console.log({
sharedKeyFromA,
sharedKeyFromB,
Expand Down

0 comments on commit b4fae83

Please sign in to comment.