init: v1.0.0
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
## 20230321-v1.6.1
|
||||
gcl/x/tpc移到gcl/tpc
|
||||
gcl/tpc增加SM9协同签名、解密、密钥解封装
|
||||
|
||||
## 20230128-v1.5.0
|
||||
Add SM4_RNG.
|
||||
|
||||
## 20230118-v1.4.7
|
||||
Add DRNG and SM3_RNG.
|
||||
|
||||
## 20221125-v1.4.6
|
||||
Fix Issue 5
|
||||
## 20221125-v1.4.5
|
||||
Typo&Tidy
|
||||
|
||||
## 20221117-v1.4.4
|
||||
fix Issue 4
|
||||
|
||||
## 20220810-v1.4.1
|
||||
- Replace all error returns from `gcl` with `errorchain.Error`.
|
||||
- Review package `utils/blockmod`, replace panic with error.
|
||||
- `utils/blockmode.NewCTR`增加返回error.
|
||||
|
||||
|
||||
## 20220809-v1.4.0
|
||||
- `sm9.Sign`函数签名更改,增加返回错误.
|
||||
- `sm9.KeyEncapsule`函数签名更改,增加rnd输入类型,增加返回错误.
|
||||
- 增加加密函数
|
||||
```go
|
||||
func Encrypt(encType EncType, pube *MastEncPublicKey, id, plain []byte, rand io.Reader, optionalIV []byte) (*Cipher, error)
|
||||
```
|
||||
- 增加解密函数
|
||||
```go
|
||||
func Decrypt(id []byte, c *Cipher, de *UserEncKey) ([]byte, error)
|
||||
```
|
||||
|
||||
注1:如果是外部产生随机数,如自测用的标准数据,则用`bytes.NewReader(b []byte)`得到一个`io.Reader`.
|
||||
|
||||
注2:注1的方法临时或测试用,生产环境应将外部随机源包装为一个`io.Reader`,因为注1的方法读取`len(b)`字节后会报`io.EOF`错误.
|
||||
|
||||
注3:除安审,使用`grand.Reader`(e.g. `crypto/Rand.Reader`-Linux上是读取`/dev/(u)random`)已足够。
|
||||
|
||||
## 20211120
|
||||
- amd64平台,SM4 SIMD汇编实现。
|
||||
- SM4 ECB 单线程 250MBps
|
||||
|
||||
## 20211119
|
||||
- 移除x509到gssl
|
||||
- 在支持SIMD的amd64平台下,SM4 ECB模式性能翻倍(单线程 > 1.2Gbps)
|
||||
> arm64平台、CTR和GCM模式未完待续
|
||||
|
||||
## 20210901
|
||||
- 增加x509,sharing/ssss
|
||||
|
||||
## 2021-0331
|
||||
- 增加sm/sm2v1包
|
||||
- sm/sm2v1是go标准库风格的签名库。与ecdsa调用方式兼容。
|
||||
> 用于方便替换ecdsa签名
|
||||
|
||||
## 2020-0916
|
||||
- 增加SM4-GCM模式
|
||||
|
||||
## 20200901
|
||||
### SM9
|
||||
#### Signature 结构
|
||||
```go
|
||||
// before
|
||||
type Signature struct {
|
||||
H *big.Int
|
||||
S *G1
|
||||
}
|
||||
|
||||
// now
|
||||
type Signature struct {
|
||||
H big.Int
|
||||
S G1
|
||||
}
|
||||
```
|
||||
|
||||
#### 加密类型
|
||||
`ENC_TYPE_XXX` change to `oid.xxx`(GM/T 0006修订稿加入SM9)
|
||||
|
||||
## 20200701
|
||||
- add assemble implements on amd64 and arm64
|
||||
|
||||
## 20190318
|
||||
- version 0.1
|
||||
@@ -0,0 +1,162 @@
|
||||
# Summary
|
||||
|
||||
xdx (Golang) Crypto Library
|
||||
|
||||
Author: xdx
|
||||
|
||||
Package gcl is the xdx (Golang) Crypto Library of GOLANG(Go语言版的密码函数库)
|
||||
|
||||
包说明:
|
||||
- identifier (GM/T 0006 密码标识常量定义)
|
||||
- rsa - pkcs #1 v1.5 签名、SDF_XX_RSA接口实现 - Wrapping of crypto/rsa
|
||||
- sm/sm1
|
||||
- sm/sm2
|
||||
- sm/sm3
|
||||
- sm/sm4 包括CTR and GCM模式, sm4_mac
|
||||
- pbkd P5,口令派生密钥规范
|
||||
- grand 随机数
|
||||
- drgb(确定性随机数发生器,软件实现的伪随机数生成器,密标草案稿,包括sm3_rng和sm4_ctr两个发生器)
|
||||
- statistics - deprecated, use xdx.jelly/rts instead。
|
||||
- MAC - 包括cbcmac, hmac_sm3 - hmac建议直接用hmac.New
|
||||
- utils
|
||||
- p7 padding (p5 padding is a special case of p7,utils/padding)
|
||||
- tpc - SM2和SM9的协同签名(for HooFoo)
|
||||
- x 新功能开发, 开发完成会放到gcl包下(不保证接口不变)
|
||||
- 合并签名(x/seal/concentration)
|
||||
|
||||
|
||||
# HOWTO
|
||||
- gcl文件夹需放在GOPATH/xdx.jelly/文件夹下
|
||||
- 需要golang.org/x/sys包
|
||||
|
||||
# Endian
|
||||
SM2和SM9可以设置按0018中序列化时,ULONG转换的大小端序。比如10进制数256:
|
||||
- 大端:256 => 00 00 01 00
|
||||
- 小端:256 => 00 01 00 00
|
||||
|
||||
默认是大端序。若要指定端序,使用下面的函数(只需执行一次)
|
||||
|
||||
```go
|
||||
// 设置SM2,SM9转换端序
|
||||
sm.SetToBigEndian()
|
||||
sm.SetToLittleEndian()
|
||||
```
|
||||
|
||||
```go
|
||||
// 设置SM2转换端序
|
||||
sm2.SetToBigEndian()
|
||||
sm2.SetToLittleEndian()
|
||||
```
|
||||
|
||||
|
||||
```go
|
||||
// 设置SM9转换端序
|
||||
sm9.SetToBigEndian()
|
||||
sm9.SetToLittleEndian()
|
||||
```
|
||||
|
||||
注:反序列化Unmarshal的时候,默认忽略输入的bits的大小端序,不做严格检查。
|
||||
|
||||
# 函数调用约定
|
||||
## 若返回错误,则保证输入不变,输出无意义。
|
||||
```
|
||||
out, err = fn(param)
|
||||
```
|
||||
若err != nil, 则param不变,out可能为nil,空Slice,零值或其他无意义数据。
|
||||
|
||||
如果函数调用可能发生错误,则下面这样调用发生错误时原输入值会丢失。
|
||||
```
|
||||
a, err = fn(a)
|
||||
```
|
||||
|
||||
## 输入随机数
|
||||
|
||||
函数需要输入随机数的地方均可用nil代替,则函数内部使用grand的随机数发生器。
|
||||
|
||||
## 避免堆上分配空间
|
||||
SM4的加解密,可以提前栈上分配好内存空间,传入函数调用。
|
||||
例如
|
||||
```
|
||||
func EncryptECB(dst, key, src []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
dst和src要么完全重叠,要么不重叠
|
||||
|
||||
dst可以有三种情况
|
||||
- nil, 内部分配空间,必须接收函数返回
|
||||
- len(dst) >= len(src), 结果写入dst[:len(src)]并返回
|
||||
- len(dst) < len(src), 分两种情况:
|
||||
- cap(dst) >= len(src), 则不会发生内存重分配, 返回dst[:len(src)]
|
||||
- cap(dst) < len(src), 内存重分配, 返回dst[:len(src)], 注意这时输入的dst和返回值是指向不同的内存地址。
|
||||
|
||||
应尽量避免内存重分配。涉及内存分配和拷贝
|
||||
|
||||
示例
|
||||
```
|
||||
|
||||
data := [128]byte // set enough length on stack
|
||||
src := data[:64]
|
||||
|
||||
|
||||
// first case
|
||||
dst, err := EncryptECB(nil, key, src) // dst is allocate in EncryptECB
|
||||
if (err != nil){
|
||||
// error handle
|
||||
}
|
||||
|
||||
// second case
|
||||
// 原地加密,src中现在存的是密文。
|
||||
_, err := EncryptECB(src, key, src)
|
||||
if (err != nil){
|
||||
// error handle
|
||||
// 若出错,src中内容不变,为明文
|
||||
}
|
||||
|
||||
dst := data[96:]
|
||||
dst, err = EncryptECB(dst, key, src) // len(dst)不够,且cap(dst) < len(src), 重分配内存。
|
||||
if (err != nil){
|
||||
// error handle
|
||||
}
|
||||
```
|
||||
|
||||
**最后,如果还是不知道dst应该输入什么,那就输入nil**
|
||||
|
||||
- 输入参数应该尽量保证不变(除说明外)。但有几个例外:
|
||||
```
|
||||
func CBCEncrypt(dst, iv, key, src []byte) ([]byte, error)
|
||||
```
|
||||
CBC模式会改变iv的值,作为下一次调用的输入。
|
||||
|
||||
- SM4的相关加解密函数如果确保输入数据长度都是正确的,那么可以不检查返回error
|
||||
- SM4可以使用与go标准库一样的步骤。进行其他modes的加解密。
|
||||
```
|
||||
block, err := NewCipher(key)
|
||||
decrypter := cipher.NewCBCDecrypter(block, iv)
|
||||
decrypter.CryptBlocks(out, in)
|
||||
```
|
||||
# Marshal & Unmarshal
|
||||
|
||||
- gcl/util/encoding/{UtilMarshaler,UtilUnmarshaler}接口实现gmt0018的数据格式和类型的序列化。(增加输入缓存区和返回销毁字节数)
|
||||
- x.MarshalBinary/x.UnmarshalBinary-弃用,使用上一条代替。
|
||||
- x.MarshalSDF/x.UnmarshalSDF实现和SDF数据结构的相互转换。
|
||||
- x.MarshalASN1/x.UnmarshalANS1 (TODO), 实现`SM{2,9}算法使用规范`的ANS.1编解码转换。
|
||||
|
||||
# Benchmark
|
||||
|
||||
## SM2 on amd64
|
||||
- sign: 40000
|
||||
- Verify: 13500
|
||||
|
||||
## SM3 on amd64
|
||||
- AVX2: ~400MBps
|
||||
|
||||
## SM4 on amd64
|
||||
- ECB: 250MBps(SM4-AESNI)
|
||||
- GCM: (TODO: use SM4-AESNI and PCLMULQDQ)
|
||||
|
||||
## SM9 on amd64
|
||||
- sign: 1500
|
||||
|
||||
|
||||
# RoadMap
|
||||
- 按sm2/sm9使用规范的ASN.1序列化和反序列化。
|
||||
@@ -0,0 +1,266 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package des
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) {
|
||||
b := binary.BigEndian.Uint64(src)
|
||||
b = permuteInitialBlock(b)
|
||||
left, right := uint32(b>>32), uint32(b)
|
||||
|
||||
left = (left << 1) | (left >> 31)
|
||||
right = (right << 1) | (right >> 31)
|
||||
|
||||
if decrypt {
|
||||
for i := 0; i < 8; i++ {
|
||||
left, right = feistel(left, right, subkeys[15-2*i], subkeys[15-(2*i+1)])
|
||||
fmt.Printf("%d:%08x %08x\n", i, left, right)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < 8; i++ {
|
||||
left, right = feistel(left, right, subkeys[2*i], subkeys[2*i+1])
|
||||
fmt.Printf("%d:%08x %08x\n", i, left, right)
|
||||
}
|
||||
}
|
||||
|
||||
left = (left << 31) | (left >> 1)
|
||||
right = (right << 31) | (right >> 1)
|
||||
|
||||
// switch left & right and perform final permutation
|
||||
preOutput := (uint64(right) << 32) | uint64(left)
|
||||
binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput))
|
||||
}
|
||||
|
||||
// Encrypt one block from src into dst, using the subkeys.
|
||||
func encryptBlock(subkeys []uint64, dst, src []byte) {
|
||||
cryptBlock(subkeys, dst, src, false)
|
||||
}
|
||||
|
||||
// Decrypt one block from src into dst, using the subkeys.
|
||||
func decryptBlock(subkeys []uint64, dst, src []byte) {
|
||||
cryptBlock(subkeys, dst, src, true)
|
||||
}
|
||||
|
||||
// DES Feistel function. feistelBox must be initialized via
|
||||
// feistelBoxOnce.Do(initFeistelBox) first.
|
||||
func feistel(l, r uint32, k0, k1 uint64) (lout, rout uint32) {
|
||||
var t uint32
|
||||
|
||||
t = r ^ uint32(k0>>32)
|
||||
l ^= feistelBox[7][t&0x3f] ^
|
||||
feistelBox[5][(t>>8)&0x3f] ^
|
||||
feistelBox[3][(t>>16)&0x3f] ^
|
||||
feistelBox[1][(t>>24)&0x3f]
|
||||
|
||||
t = ((r << 28) | (r >> 4)) ^ uint32(k0)
|
||||
l ^= feistelBox[6][(t)&0x3f] ^
|
||||
feistelBox[4][(t>>8)&0x3f] ^
|
||||
feistelBox[2][(t>>16)&0x3f] ^
|
||||
feistelBox[0][(t>>24)&0x3f]
|
||||
|
||||
t = l ^ uint32(k1>>32)
|
||||
r ^= feistelBox[7][t&0x3f] ^
|
||||
feistelBox[5][(t>>8)&0x3f] ^
|
||||
feistelBox[3][(t>>16)&0x3f] ^
|
||||
feistelBox[1][(t>>24)&0x3f]
|
||||
|
||||
t = ((l << 28) | (l >> 4)) ^ uint32(k1)
|
||||
r ^= feistelBox[6][(t)&0x3f] ^
|
||||
feistelBox[4][(t>>8)&0x3f] ^
|
||||
feistelBox[2][(t>>16)&0x3f] ^
|
||||
feistelBox[0][(t>>24)&0x3f]
|
||||
|
||||
return l, r
|
||||
}
|
||||
|
||||
// feistelBox[s][16*i+j] contains the output of permutationFunction
|
||||
// for sBoxes[s][i][j] << 4*(7-s)
|
||||
var feistelBox [8][64]uint32
|
||||
|
||||
var feistelBoxOnce sync.Once
|
||||
|
||||
// general purpose function to perform DES block permutations
|
||||
func permuteBlock(src uint64, permutation []uint8) (block uint64) {
|
||||
for position, n := range permutation {
|
||||
bit := (src >> n) & 1
|
||||
block |= bit << uint((len(permutation)-1)-position)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func initFeistelBox() {
|
||||
for s := range sBoxes {
|
||||
for i := 0; i < 4; i++ {
|
||||
for j := 0; j < 16; j++ {
|
||||
f := uint64(sBoxes[s][i][j]) << (4 * (7 - uint(s)))
|
||||
f = permuteBlock(f, permutationFunction[:])
|
||||
|
||||
// Row is determined by the 1st and 6th bit.
|
||||
// Column is the middle four bits.
|
||||
row := uint8(((i & 2) << 4) | i&1)
|
||||
col := uint8(j << 1)
|
||||
t := row | col
|
||||
|
||||
// The rotation was performed in the feistel rounds, being factored out and now mixed into the feistelBox.
|
||||
f = (f << 1) | (f >> 31)
|
||||
|
||||
feistelBox[s][t] = uint32(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// permuteInitialBlock is equivalent to the permutation defined
|
||||
// by initialPermutation.
|
||||
func permuteInitialBlock(block uint64) uint64 {
|
||||
// block = b7 b6 b5 b4 b3 b2 b1 b0 (8 bytes)
|
||||
b1 := block >> 48
|
||||
b2 := block << 48
|
||||
block ^= b1 ^ b2 ^ b1<<48 ^ b2>>48
|
||||
|
||||
// block = b1 b0 b5 b4 b3 b2 b7 b6
|
||||
b1 = block >> 32 & 0xff00ff
|
||||
b2 = (block & 0xff00ff00)
|
||||
block ^= b1<<32 ^ b2 ^ b1<<8 ^ b2<<24 // exchange b0 b4 with b3 b7
|
||||
|
||||
// block is now b1 b3 b5 b7 b0 b2 b4 b7, the permutation:
|
||||
// ... 8
|
||||
// ... 24
|
||||
// ... 40
|
||||
// ... 56
|
||||
// 7 6 5 4 3 2 1 0
|
||||
// 23 22 21 20 19 18 17 16
|
||||
// ... 32
|
||||
// ... 48
|
||||
|
||||
// exchange 4,5,6,7 with 32,33,34,35 etc.
|
||||
b1 = block & 0x0f0f00000f0f0000
|
||||
b2 = block & 0x0000f0f00000f0f0
|
||||
block ^= b1 ^ b2 ^ b1>>12 ^ b2<<12
|
||||
|
||||
// block is the permutation:
|
||||
//
|
||||
// [+8] [+40]
|
||||
//
|
||||
// 7 6 5 4
|
||||
// 23 22 21 20
|
||||
// 3 2 1 0
|
||||
// 19 18 17 16 [+32]
|
||||
|
||||
// exchange 0,1,4,5 with 18,19,22,23
|
||||
b1 = block & 0x3300330033003300
|
||||
b2 = block & 0x00cc00cc00cc00cc
|
||||
block ^= b1 ^ b2 ^ b1>>6 ^ b2<<6
|
||||
|
||||
// block is the permutation:
|
||||
// 15 14
|
||||
// 13 12
|
||||
// 11 10
|
||||
// 9 8
|
||||
// 7 6
|
||||
// 5 4
|
||||
// 3 2
|
||||
// 1 0 [+16] [+32] [+64]
|
||||
|
||||
// exchange 0,2,4,6 with 9,11,13,15:
|
||||
b1 = block & 0xaaaaaaaa55555555
|
||||
block ^= b1 ^ b1>>33 ^ b1<<33
|
||||
|
||||
// block is the permutation:
|
||||
// 6 14 22 30 38 46 54 62
|
||||
// 4 12 20 28 36 44 52 60
|
||||
// 2 10 18 26 34 42 50 58
|
||||
// 0 8 16 24 32 40 48 56
|
||||
// 7 15 23 31 39 47 55 63
|
||||
// 5 13 21 29 37 45 53 61
|
||||
// 3 11 19 27 35 43 51 59
|
||||
// 1 9 17 25 33 41 49 57
|
||||
return block
|
||||
}
|
||||
|
||||
// permuteInitialBlock is equivalent to the permutation defined
|
||||
// by finalPermutation.
|
||||
func permuteFinalBlock(block uint64) uint64 {
|
||||
// Perform the same bit exchanges as permuteInitialBlock
|
||||
// but in reverse order.
|
||||
b1 := block & 0xaaaaaaaa55555555
|
||||
block ^= b1 ^ b1>>33 ^ b1<<33
|
||||
|
||||
b1 = block & 0x3300330033003300
|
||||
b2 := block & 0x00cc00cc00cc00cc
|
||||
block ^= b1 ^ b2 ^ b1>>6 ^ b2<<6
|
||||
|
||||
b1 = block & 0x0f0f00000f0f0000
|
||||
b2 = block & 0x0000f0f00000f0f0
|
||||
block ^= b1 ^ b2 ^ b1>>12 ^ b2<<12
|
||||
|
||||
b1 = block >> 32 & 0xff00ff
|
||||
b2 = (block & 0xff00ff00)
|
||||
block ^= b1<<32 ^ b2 ^ b1<<8 ^ b2<<24
|
||||
|
||||
b1 = block >> 48
|
||||
b2 = block << 48
|
||||
block ^= b1 ^ b2 ^ b1<<48 ^ b2>>48
|
||||
return block
|
||||
}
|
||||
|
||||
// creates 16 28-bit blocks rotated according
|
||||
// to the rotation schedule
|
||||
func ksRotate(in uint32) (out []uint32) {
|
||||
out = make([]uint32, 16)
|
||||
last := in
|
||||
for i := 0; i < 16; i++ {
|
||||
// 28-bit circular left shift
|
||||
left := (last << (4 + ksRotations[i])) >> 4
|
||||
right := (last << 4) >> (32 - ksRotations[i])
|
||||
out[i] = left | right
|
||||
last = out[i]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// creates 16 56-bit subkeys from the original key
|
||||
func (c *desCipher) generateSubkeys(keyBytes []byte) {
|
||||
feistelBoxOnce.Do(initFeistelBox)
|
||||
|
||||
// apply PC1 permutation to key
|
||||
key := binary.BigEndian.Uint64(keyBytes)
|
||||
permutedKey := permuteBlock(key, permutedChoice1[:])
|
||||
|
||||
// rotate halves of permuted key according to the rotation schedule
|
||||
leftRotations := ksRotate(uint32(permutedKey >> 28))
|
||||
rightRotations := ksRotate(uint32(permutedKey<<4) >> 4)
|
||||
|
||||
// generate subkeys
|
||||
for i := 0; i < 16; i++ {
|
||||
// combine halves to form 56-bit input to PC2
|
||||
pc2Input := uint64(leftRotations[i])<<28 | uint64(rightRotations[i])
|
||||
// apply PC2 permutation to 7 byte input
|
||||
c.subkeys[i] = unpack(permuteBlock(pc2Input, permutedChoice2[:]))
|
||||
}
|
||||
}
|
||||
|
||||
// Expand 48-bit input to 64-bit, with each 6-bit block padded by extra two bits at the top.
|
||||
// By doing so, we can have the input blocks (four bits each), and the key blocks (six bits each) well-aligned without
|
||||
// extra shifts/rotations for alignments.
|
||||
func unpack(x uint64) uint64 {
|
||||
var result uint64
|
||||
|
||||
result = ((x>>(6*1))&0xff)<<(8*0) |
|
||||
((x>>(6*3))&0xff)<<(8*1) |
|
||||
((x>>(6*5))&0xff)<<(8*2) |
|
||||
((x>>(6*7))&0xff)<<(8*3) |
|
||||
((x>>(6*0))&0xff)<<(8*4) |
|
||||
((x>>(6*2))&0xff)<<(8*5) |
|
||||
((x>>(6*4))&0xff)<<(8*6) |
|
||||
((x>>(6*6))&0xff)<<(8*7)
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package des
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"strconv"
|
||||
|
||||
"xdx.jelly/xgcl/internal/subtle"
|
||||
)
|
||||
|
||||
// The DES block size in bytes.
|
||||
const BlockSize = 8
|
||||
|
||||
type KeySizeError int
|
||||
|
||||
func (k KeySizeError) Error() string {
|
||||
return "crypto/des: invalid key size " + strconv.Itoa(int(k))
|
||||
}
|
||||
|
||||
// desCipher is an instance of DES encryption.
|
||||
type desCipher struct {
|
||||
subkeys [16]uint64
|
||||
}
|
||||
|
||||
// NewCipher creates and returns a new cipher.Block.
|
||||
func NewCipher(key []byte) (cipher.Block, error) {
|
||||
if len(key) != 8 {
|
||||
return nil, KeySizeError(len(key))
|
||||
}
|
||||
|
||||
c := new(desCipher)
|
||||
c.generateSubkeys(key)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *desCipher) BlockSize() int { return BlockSize }
|
||||
|
||||
func (c *desCipher) Encrypt(dst, src []byte) {
|
||||
if len(src) < BlockSize {
|
||||
panic("crypto/des: input not full block")
|
||||
}
|
||||
if len(dst) < BlockSize {
|
||||
panic("crypto/des: output not full block")
|
||||
}
|
||||
if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
||||
panic("crypto/des: invalid buffer overlap")
|
||||
}
|
||||
encryptBlock(c.subkeys[:], dst, src)
|
||||
}
|
||||
|
||||
func (c *desCipher) Decrypt(dst, src []byte) {
|
||||
if len(src) < BlockSize {
|
||||
panic("crypto/des: input not full block")
|
||||
}
|
||||
if len(dst) < BlockSize {
|
||||
panic("crypto/des: output not full block")
|
||||
}
|
||||
if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
||||
panic("crypto/des: invalid buffer overlap")
|
||||
}
|
||||
decryptBlock(c.subkeys[:], dst, src)
|
||||
}
|
||||
|
||||
// A tripleDESCipher is an instance of TripleDES encryption.
|
||||
type tripleDESCipher struct {
|
||||
cipher1, cipher2, cipher3 desCipher
|
||||
}
|
||||
|
||||
// NewTripleDESCipher creates and returns a new cipher.Block.
|
||||
func NewTripleDESCipher(key []byte) (cipher.Block, error) {
|
||||
if len(key) != 24 {
|
||||
return nil, KeySizeError(len(key))
|
||||
}
|
||||
|
||||
c := new(tripleDESCipher)
|
||||
c.cipher1.generateSubkeys(key[:8])
|
||||
c.cipher2.generateSubkeys(key[8:16])
|
||||
c.cipher3.generateSubkeys(key[16:])
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *tripleDESCipher) BlockSize() int { return BlockSize }
|
||||
|
||||
func (c *tripleDESCipher) Encrypt(dst, src []byte) {
|
||||
if len(src) < BlockSize {
|
||||
panic("crypto/des: input not full block")
|
||||
}
|
||||
if len(dst) < BlockSize {
|
||||
panic("crypto/des: output not full block")
|
||||
}
|
||||
if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
||||
panic("crypto/des: invalid buffer overlap")
|
||||
}
|
||||
|
||||
b := binary.BigEndian.Uint64(src)
|
||||
b = permuteInitialBlock(b)
|
||||
left, right := uint32(b>>32), uint32(b)
|
||||
|
||||
left = (left << 1) | (left >> 31)
|
||||
right = (right << 1) | (right >> 31)
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
left, right = feistel(left, right, c.cipher1.subkeys[2*i], c.cipher1.subkeys[2*i+1])
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
right, left = feistel(right, left, c.cipher2.subkeys[15-2*i], c.cipher2.subkeys[15-(2*i+1)])
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
left, right = feistel(left, right, c.cipher3.subkeys[2*i], c.cipher3.subkeys[2*i+1])
|
||||
}
|
||||
|
||||
left = (left << 31) | (left >> 1)
|
||||
right = (right << 31) | (right >> 1)
|
||||
|
||||
preOutput := (uint64(right) << 32) | uint64(left)
|
||||
binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput))
|
||||
}
|
||||
|
||||
func (c *tripleDESCipher) Decrypt(dst, src []byte) {
|
||||
if len(src) < BlockSize {
|
||||
panic("crypto/des: input not full block")
|
||||
}
|
||||
if len(dst) < BlockSize {
|
||||
panic("crypto/des: output not full block")
|
||||
}
|
||||
if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
|
||||
panic("crypto/des: invalid buffer overlap")
|
||||
}
|
||||
|
||||
b := binary.BigEndian.Uint64(src)
|
||||
b = permuteInitialBlock(b)
|
||||
left, right := uint32(b>>32), uint32(b)
|
||||
|
||||
left = (left << 1) | (left >> 31)
|
||||
right = (right << 1) | (right >> 31)
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
left, right = feistel(left, right, c.cipher3.subkeys[15-2*i], c.cipher3.subkeys[15-(2*i+1)])
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
right, left = feistel(right, left, c.cipher2.subkeys[2*i], c.cipher2.subkeys[2*i+1])
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
left, right = feistel(left, right, c.cipher1.subkeys[15-2*i], c.cipher1.subkeys[15-(2*i+1)])
|
||||
}
|
||||
|
||||
left = (left << 31) | (left >> 1)
|
||||
right = (right << 31) | (right >> 1)
|
||||
|
||||
preOutput := (uint64(right) << 32) | uint64(left)
|
||||
binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput))
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package des implements the Data Encryption Standard (DES) and the
|
||||
// Triple Data Encryption Algorithm (TDEA) as defined
|
||||
// in U.S. Federal Information Processing Standards Publication 46-3.
|
||||
//
|
||||
// DES is cryptographically broken and should not be used for secure
|
||||
// applications.
|
||||
package des
|
||||
|
||||
// Used to perform an initial permutation of a 64-bit input block.
|
||||
var initialPermutation = [64]byte{
|
||||
6, 14, 22, 30, 38, 46, 54, 62,
|
||||
4, 12, 20, 28, 36, 44, 52, 60,
|
||||
2, 10, 18, 26, 34, 42, 50, 58,
|
||||
0, 8, 16, 24, 32, 40, 48, 56,
|
||||
7, 15, 23, 31, 39, 47, 55, 63,
|
||||
5, 13, 21, 29, 37, 45, 53, 61,
|
||||
3, 11, 19, 27, 35, 43, 51, 59,
|
||||
1, 9, 17, 25, 33, 41, 49, 57,
|
||||
}
|
||||
|
||||
// Used to perform a final permutation of a 4-bit preoutput block. This is the
|
||||
// inverse of initialPermutation
|
||||
var finalPermutation = [64]byte{
|
||||
24, 56, 16, 48, 8, 40, 0, 32,
|
||||
25, 57, 17, 49, 9, 41, 1, 33,
|
||||
26, 58, 18, 50, 10, 42, 2, 34,
|
||||
27, 59, 19, 51, 11, 43, 3, 35,
|
||||
28, 60, 20, 52, 12, 44, 4, 36,
|
||||
29, 61, 21, 53, 13, 45, 5, 37,
|
||||
30, 62, 22, 54, 14, 46, 6, 38,
|
||||
31, 63, 23, 55, 15, 47, 7, 39,
|
||||
}
|
||||
|
||||
// Used to expand an input block of 32 bits, producing an output block of 48
|
||||
// bits.
|
||||
var expansionFunction = [48]byte{
|
||||
0, 31, 30, 29, 28, 27, 28, 27,
|
||||
26, 25, 24, 23, 24, 23, 22, 21,
|
||||
20, 19, 20, 19, 18, 17, 16, 15,
|
||||
16, 15, 14, 13, 12, 11, 12, 11,
|
||||
10, 9, 8, 7, 8, 7, 6, 5,
|
||||
4, 3, 4, 3, 2, 1, 0, 31,
|
||||
}
|
||||
|
||||
// Yields a 32-bit output from a 32-bit input
|
||||
var permutationFunction = [32]byte{
|
||||
16, 25, 12, 11, 3, 20, 4, 15,
|
||||
31, 17, 9, 6, 27, 14, 1, 22,
|
||||
30, 24, 8, 18, 0, 5, 29, 23,
|
||||
13, 19, 2, 26, 10, 21, 28, 7,
|
||||
}
|
||||
|
||||
// Used in the key schedule to select 56 bits
|
||||
// from a 64-bit input.
|
||||
var permutedChoice1 = [56]byte{
|
||||
7, 15, 23, 31, 39, 47, 55, 63,
|
||||
6, 14, 22, 30, 38, 46, 54, 62,
|
||||
5, 13, 21, 29, 37, 45, 53, 61,
|
||||
4, 12, 20, 28, 1, 9, 17, 25,
|
||||
33, 41, 49, 57, 2, 10, 18, 26,
|
||||
34, 42, 50, 58, 3, 11, 19, 27,
|
||||
35, 43, 51, 59, 36, 44, 52, 60,
|
||||
}
|
||||
|
||||
// Used in the key schedule to produce each subkey by selecting 48 bits from
|
||||
// the 56-bit input
|
||||
var permutedChoice2 = [48]byte{
|
||||
42, 39, 45, 32, 55, 51, 53, 28,
|
||||
41, 50, 35, 46, 33, 37, 44, 52,
|
||||
30, 48, 40, 49, 29, 36, 43, 54,
|
||||
15, 4, 25, 19, 9, 1, 26, 16,
|
||||
5, 11, 23, 8, 12, 7, 17, 0,
|
||||
22, 3, 10, 14, 6, 20, 27, 24,
|
||||
}
|
||||
|
||||
// 8 S-boxes composed of 4 rows and 16 columns
|
||||
// Used in the DES cipher function
|
||||
var sBoxes = [8][4][16]uint8{
|
||||
// S-box 1
|
||||
{
|
||||
{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
|
||||
{0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
|
||||
{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
|
||||
{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
|
||||
},
|
||||
// S-box 2
|
||||
{
|
||||
{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
|
||||
{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
|
||||
{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
|
||||
{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
|
||||
},
|
||||
// S-box 3
|
||||
{
|
||||
{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
|
||||
{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
|
||||
{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
|
||||
{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
|
||||
},
|
||||
// S-box 4
|
||||
{
|
||||
{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
|
||||
{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
|
||||
{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
|
||||
{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
|
||||
},
|
||||
// S-box 5
|
||||
{
|
||||
{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
|
||||
{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
|
||||
{4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
|
||||
{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
|
||||
},
|
||||
// S-box 6
|
||||
{
|
||||
{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
|
||||
{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
|
||||
{9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
|
||||
{4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13},
|
||||
},
|
||||
// S-box 7
|
||||
{
|
||||
{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
|
||||
{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
|
||||
{1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
|
||||
{6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12},
|
||||
},
|
||||
// S-box 8
|
||||
{
|
||||
{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
|
||||
{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
|
||||
{7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
|
||||
{2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11},
|
||||
},
|
||||
}
|
||||
|
||||
// Size of left rotation per round in each half of the key schedule
|
||||
var ksRotations = [16]uint8{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package des_test
|
||||
|
||||
import "crypto/des"
|
||||
|
||||
func ExampleNewTripleDESCipher() {
|
||||
// NewTripleDESCipher can also be used when EDE2 is required by
|
||||
// duplicating the first 8 bytes of the 16-byte key.
|
||||
ede2Key := []byte("example key 1234")
|
||||
|
||||
var tripleDESKey []byte
|
||||
tripleDESKey = append(tripleDESKey, ede2Key[:16]...)
|
||||
tripleDESKey = append(tripleDESKey, ede2Key[:8]...)
|
||||
|
||||
_, err := des.NewTripleDESCipher(tripleDESKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// See crypto/cipher for how to use a cipher.Block for encryption and
|
||||
// decryption.
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// package antique is the out-of-date crypto algorithms/protocal.
|
||||
// For learning and interest purposes only.
|
||||
// DO NOT USE ANY OF THEM.
|
||||
|
||||
package antique
|
||||
@@ -0,0 +1,3 @@
|
||||
package baseline
|
||||
|
||||
// 对接口的基线检测
|
||||
@@ -0,0 +1,6 @@
|
||||
package baseline
|
||||
|
||||
type SdfChecker struct {
|
||||
}
|
||||
|
||||
// TODO
|
||||
@@ -0,0 +1,112 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type SDRError uint32
|
||||
|
||||
const (
|
||||
SDR_OK SDRError = 0x0 // 操作成功
|
||||
SDR_BASE SDRError = 0x01000000 // 错误码基础值
|
||||
SDR_UNKNOWERR SDRError = SDR_BASE + 0x00000001 // 未知错误
|
||||
SDR_NOTSUPPORT SDRError = SDR_BASE + 0x00000002 // 不支持的接口调用
|
||||
SDR_COMMFAIL SDRError = SDR_BASE + 0x00000003 // 与设备通信失败
|
||||
SDR_HARDFAIL SDRError = SDR_BASE + 0x00000004 // 运算模块无响应
|
||||
SDR_OPENDEVICE SDRError = SDR_BASE + 0x00000005 // 打开设备失败
|
||||
SDR_OPENSESSION SDRError = SDR_BASE + 0x00000006 // 创建会话失败
|
||||
SDR_PARDENY SDRError = SDR_BASE + 0x00000007 // 无私钥使用权限
|
||||
SDR_KEYNOTEXIST SDRError = SDR_BASE + 0x00000008 // 不存在的密钥调用
|
||||
SDR_ALGNOTSUPPORT SDRError = SDR_BASE + 0x00000009 // 不支持的算法调用
|
||||
SDR_ALGMODNOTSUPPORT SDRError = SDR_BASE + 0x0000000A // 不支持的算法模式调用
|
||||
SDR_PKOPERR SDRError = SDR_BASE + 0x0000000B // 公钥运算失败
|
||||
SDR_SKOPERR SDRError = SDR_BASE + 0x0000000C // 私钥运算失败
|
||||
SDR_SIGNERR SDRError = SDR_BASE + 0x0000000D // 签名运算失败
|
||||
SDR_VERIFYERR SDRError = SDR_BASE + 0x0000000E // 验证签名失败
|
||||
SDR_SYMOPERR SDRError = SDR_BASE + 0x0000000F // 对称算法运算失败
|
||||
SDR_STEPERR SDRError = SDR_BASE + 0x00000010 // 多步运算步骤错误
|
||||
SDR_FILESIZEERR SDRError = SDR_BASE + 0x00000011 // 文件长度超出限制
|
||||
SDR_FILENOEXIST SDRError = SDR_BASE + 0x00000012 // 指定的文件不存在
|
||||
SDR_FILEOFSERR SDRError = SDR_BASE + 0x00000013 // 文件起始位置错误
|
||||
SDR_KEYTYPEERR SDRError = SDR_BASE + 0x00000014 // 密钥类型错误
|
||||
SDR_KEYERR SDRError = SDR_BASE + 0x00000015 // 密钥错误
|
||||
SDR_ENCDATAERR SDRError = SDR_BASE + 0x00000016 // ECC加密数据错误
|
||||
SDR_RANDERR SDRError = SDR_BASE + 0x00000017 // 随机数产生失败
|
||||
SDR_PRKRERR SDRError = SDR_BASE + 0x00000018 // 私钥使用权限获取失败
|
||||
SDR_MACERR SDRError = SDR_BASE + 0x00000019 // MAC运算失败
|
||||
SDR_FILEEXISTS SDRError = SDR_BASE + 0x0000001A // 指定文件已存在
|
||||
SDR_FILEWERR SDRError = SDR_BASE + 0x0000001B // 文件写入失败
|
||||
SDR_NOBUFFER SDRError = SDR_BASE + 0x0000001C // 存储空间不足
|
||||
SDR_INARGERR SDRError = SDR_BASE + 0x0000001D // 输入参数错误
|
||||
SDR_OUTARGERR SDRError = SDR_BASE + 0x0000001E // 输出参数错误
|
||||
)
|
||||
|
||||
func (s SDRError) Error() string {
|
||||
return s.String()
|
||||
}
|
||||
func (s SDRError) String() string {
|
||||
switch s {
|
||||
case SDR_UNKNOWERR:
|
||||
return fmt.Sprintf("0x%08x: 未知错误", uint32(SDR_UNKNOWERR))
|
||||
case SDR_NOTSUPPORT:
|
||||
return fmt.Sprintf("0x%08x: 不支持的接口调用", uint32(SDR_NOTSUPPORT))
|
||||
case SDR_COMMFAIL:
|
||||
return fmt.Sprintf("0x%08x: 与设备通信失败", uint32(SDR_COMMFAIL))
|
||||
case SDR_HARDFAIL:
|
||||
return fmt.Sprintf("0x%08x: 运算模块无响应", uint32(SDR_HARDFAIL))
|
||||
case SDR_OPENDEVICE:
|
||||
return fmt.Sprintf("0x%08x: 打开设备失败", uint32(SDR_OPENDEVICE))
|
||||
case SDR_OPENSESSION:
|
||||
return fmt.Sprintf("0x%08x: 创建会话失败", uint32(SDR_OPENSESSION))
|
||||
case SDR_PARDENY:
|
||||
return fmt.Sprintf("0x%08x: 无私钥使用权限", uint32(SDR_PARDENY))
|
||||
case SDR_KEYNOTEXIST:
|
||||
return fmt.Sprintf("0x%08x: 不存在的密钥调用", uint32(SDR_KEYNOTEXIST))
|
||||
case SDR_ALGNOTSUPPORT:
|
||||
return fmt.Sprintf("0x%08x: 不支持的算法调用", uint32(SDR_ALGNOTSUPPORT))
|
||||
case SDR_ALGMODNOTSUPPORT:
|
||||
return fmt.Sprintf("0x%08x: 不支持的算法模式调用", uint32(SDR_ALGMODNOTSUPPORT))
|
||||
case SDR_PKOPERR:
|
||||
return fmt.Sprintf("0x%08x: 公钥运算失败", uint32(SDR_PKOPERR))
|
||||
case SDR_SKOPERR:
|
||||
return fmt.Sprintf("0x%08x: 私钥运算失败", uint32(SDR_SKOPERR))
|
||||
case SDR_SIGNERR:
|
||||
return fmt.Sprintf("0x%08x: 签名运算失败", uint32(SDR_SIGNERR))
|
||||
case SDR_VERIFYERR:
|
||||
return fmt.Sprintf("0x%08x: 验证签名失败", uint32(SDR_VERIFYERR))
|
||||
case SDR_SYMOPERR:
|
||||
return fmt.Sprintf("0x%08x: 对称算法运算失败", uint32(SDR_SYMOPERR))
|
||||
case SDR_STEPERR:
|
||||
return fmt.Sprintf("0x%08x: 多步运算步骤错误", uint32(SDR_STEPERR))
|
||||
case SDR_FILESIZEERR:
|
||||
return fmt.Sprintf("0x%08x: 文件长度超出限制", uint32(SDR_FILESIZEERR))
|
||||
case SDR_FILENOEXIST:
|
||||
return fmt.Sprintf("0x%08x: 指定的文件不存在", uint32(SDR_FILENOEXIST))
|
||||
case SDR_FILEOFSERR:
|
||||
return fmt.Sprintf("0x%08x: 文件起始位置错误", uint32(SDR_FILEOFSERR))
|
||||
case SDR_KEYTYPEERR:
|
||||
return fmt.Sprintf("0x%08x: 密钥类型错误", uint32(SDR_KEYTYPEERR))
|
||||
case SDR_KEYERR:
|
||||
return fmt.Sprintf("0x%08x: 密钥错误", uint32(SDR_KEYERR))
|
||||
case SDR_ENCDATAERR:
|
||||
return fmt.Sprintf("0x%08x: ECC加密数据错误", uint32(SDR_ENCDATAERR))
|
||||
case SDR_RANDERR:
|
||||
return fmt.Sprintf("0x%08x: 随机数产生失败", uint32(SDR_RANDERR))
|
||||
case SDR_PRKRERR:
|
||||
return fmt.Sprintf("0x%08x: 私钥使用权限获取失败", uint32(SDR_PRKRERR))
|
||||
case SDR_MACERR:
|
||||
return fmt.Sprintf("0x%08x: MAC运算失败", uint32(SDR_MACERR))
|
||||
case SDR_FILEEXISTS:
|
||||
return fmt.Sprintf("0x%08x: 指定文件已存在", uint32(SDR_FILEEXISTS))
|
||||
case SDR_FILEWERR:
|
||||
return fmt.Sprintf("0x%08x: 文件写入失败", uint32(SDR_FILEWERR))
|
||||
case SDR_NOBUFFER:
|
||||
return fmt.Sprintf("0x%08x: 存储空间不足", uint32(SDR_NOBUFFER))
|
||||
case SDR_INARGERR:
|
||||
return fmt.Sprintf("0x%08x: 输入参数错误", uint32(SDR_INARGERR))
|
||||
case SDR_OUTARGERR:
|
||||
return fmt.Sprintf("0x%08x: 输出参数错误", uint32(SDR_OUTARGERR))
|
||||
default:
|
||||
return "未知错误"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSDRError(t *testing.T) {
|
||||
fmt.Println(SDR_ENCDATAERR)
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
package common
|
||||
|
||||
/**
|
||||
sdf数据结构和sm2的数据结构方法绑定在sm2.Publickey.MarshalSDF上
|
||||
*/
|
||||
const (
|
||||
RSAref_MAX_BITS = 2048 //nolint
|
||||
RSAref_MAX_LEN = ((RSAref_MAX_BITS + 7) / 8) //nolint
|
||||
RSAref_MAX_PBITS = ((RSAref_MAX_BITS + 1) / 2) //nolint
|
||||
RSAref_MAX_PLEN = ((RSAref_MAX_PBITS + 7) / 8) //nolint
|
||||
ECCref_MAX_BITS = 512 //nolint
|
||||
ECCref_MAX_LEN = ((ECCref_MAX_BITS + 7) / 8) //nolint
|
||||
)
|
||||
|
||||
//RSArefPublicKey RSA公钥
|
||||
type RSArefPublicKey struct {
|
||||
Bits uint32
|
||||
M [RSAref_MAX_LEN]byte
|
||||
E [RSAref_MAX_LEN]byte
|
||||
}
|
||||
|
||||
//RSArefPrivateKey RSA私钥
|
||||
type RSArefPrivateKey struct {
|
||||
Bits uint32
|
||||
M [RSAref_MAX_LEN]byte
|
||||
E [RSAref_MAX_LEN]byte
|
||||
D [RSAref_MAX_LEN]byte
|
||||
Prime [2][RSAref_MAX_PLEN]byte
|
||||
Pexp [2][RSAref_MAX_PLEN]byte // Dp and Dq, Dp =
|
||||
Coef [RSAref_MAX_PLEN]byte // q^-1 mod p
|
||||
}
|
||||
|
||||
type EnvelopedRSAKey struct {
|
||||
SymmAlgID uint32 // 对称算法标识,限定ECB模式
|
||||
Bits uint32 // RSA密钥对的模长
|
||||
EncryptedPriKey [11][RSAref_MAX_PLEN]byte // RSA密钥对私钥的密文
|
||||
PubKey RSArefPublicKey // RSA密钥对的公钥
|
||||
L uint32 // 用RSA保护公钥加密的对称密钥密文长度
|
||||
C [RSAref_MAX_LEN]byte // 用RSA保护公钥加密的对称密钥密文
|
||||
}
|
||||
|
||||
//ECCrefPublicKey sm2公钥
|
||||
type ECCrefPublicKey struct {
|
||||
Bits uint32
|
||||
X [ECCref_MAX_LEN]byte
|
||||
Y [ECCref_MAX_LEN]byte
|
||||
}
|
||||
|
||||
//ECCrefPrivateKey sm2私钥
|
||||
type ECCrefPrivateKey struct {
|
||||
Bits uint32
|
||||
K [ECCref_MAX_LEN]byte
|
||||
}
|
||||
|
||||
//ECCCipher sm2加密结构
|
||||
type ECCCipher struct {
|
||||
X [ECCref_MAX_LEN]byte
|
||||
Y [ECCref_MAX_LEN]byte
|
||||
M [32]byte
|
||||
L uint32
|
||||
C []byte
|
||||
}
|
||||
|
||||
//ECCSignature sm2签名结果
|
||||
type ECCSignature struct {
|
||||
R [ECCref_MAX_LEN]byte
|
||||
S [ECCref_MAX_LEN]byte
|
||||
}
|
||||
|
||||
//EnvelopedECCKey sm2密钥保护结构
|
||||
type EnvelopedECCKey struct {
|
||||
AsymmAlgID uint32
|
||||
SymmAlgID uint32
|
||||
Bits uint32
|
||||
EncryptedPriKey [ECCref_MAX_LEN]byte
|
||||
PubKey ECCrefPublicKey
|
||||
ECCCipherBlob ECCCipher
|
||||
}
|
||||
|
||||
// //SM9MastPrivateKey SM9主私钥
|
||||
// type SM9MastPrivateKey struct {
|
||||
// Bits uint32
|
||||
// S [32]byte
|
||||
// }
|
||||
|
||||
// //SM9SignMastPublicKey 签名主公钥
|
||||
// type SM9SignMastPublicKey struct {
|
||||
// CompressType uint32
|
||||
// Bits uint32
|
||||
// Xa [32]byte
|
||||
// Xb [32]byte
|
||||
// Ya [32]byte
|
||||
// Yb [32]byte
|
||||
// }
|
||||
|
||||
// //SM9EncMastPublicKey 加密主公钥
|
||||
// type SM9EncMastPublicKey struct {
|
||||
// Bits uint32
|
||||
// X [32]byte
|
||||
// Y [32]byte
|
||||
// }
|
||||
|
||||
// //SM9UserSignPrivateKey 用户签名私钥
|
||||
// type SM9UserSignPrivateKey struct {
|
||||
// Bits uint32
|
||||
// X [32]byte
|
||||
// Y [32]byte
|
||||
// }
|
||||
|
||||
// //SM9UserEncPrivateKey 用户加密私钥
|
||||
// type SM9UserEncPrivateKey struct {
|
||||
// CompressType uint32
|
||||
// Bits uint32
|
||||
// Xa [32]byte
|
||||
// Xb [32]byte
|
||||
// Ya [32]byte
|
||||
// Yb [32]byte
|
||||
// }
|
||||
|
||||
// //SM9Cipher SM9加密数据结构
|
||||
// type SM9Cipher struct {
|
||||
// EnType uint32
|
||||
// X [32]byte
|
||||
// Y [32]byte
|
||||
// M [32]byte
|
||||
// L uint32
|
||||
// C [1024]byte
|
||||
// }
|
||||
|
||||
// //SM9Signature SM9签名数据结构
|
||||
// type SM9Signature struct {
|
||||
// H [32]byte
|
||||
// X [32]byte
|
||||
// Y [32]byte
|
||||
// }
|
||||
|
||||
// //SM9KeyPackage SM9密钥封装数据结构
|
||||
// type SM9KeyPackage struct {
|
||||
// K [32]byte
|
||||
// X [32]byte
|
||||
// Y [32]byte
|
||||
// }
|
||||
|
||||
// //SM9PairEncEnvelopedKey SM9用户加密密钥对保护结构
|
||||
// type SM9PairEncEnvelopedKey struct {
|
||||
// Version uint32
|
||||
// SymAlgID uint32
|
||||
// ASymmAlgID uint32
|
||||
// Bits uint32
|
||||
// EncryptedPriKey [128]byte
|
||||
// EncMastPubKey SM9EncMastPublicKey
|
||||
// UserIDLen uint32
|
||||
// UserID [1024]byte
|
||||
// PairCipher SM9Cipher
|
||||
// }
|
||||
|
||||
// //SM9PairSignEnvelopedKey SM9用户签名密钥对保护结构
|
||||
// type SM9PairSignEnvelopedKey struct {
|
||||
// Version uint32
|
||||
// SymAlgID uint32
|
||||
// ASymmAlgID uint32
|
||||
// Bits uint32
|
||||
// EncryptedPriKey [64]byte
|
||||
// SignMastPubKey SM9SignMastPublicKey
|
||||
// UserIDLen uint32
|
||||
// UserID [1024]byte
|
||||
// PairCipher SM9Cipher
|
||||
// }
|
||||
|
||||
// func (e *ECCrefPrivateKey) MarshalGcl() *sm2.PrivateKey {
|
||||
// sk := &sm2.PrivateKey{
|
||||
// D: new(big.Int).SetBytes(e.K[:]),
|
||||
// }
|
||||
// pk := sm2.GenPublicKey(sk)
|
||||
// sk.PublicKey = *pk
|
||||
// return sk
|
||||
// }
|
||||
|
||||
// func (e *ECCrefPrivateKey) UnmarshalGcl(sk *sm2.PrivateKey) error {
|
||||
// return gmath.FillBytes(sk.D, e.K[:])
|
||||
// }
|
||||
@@ -0,0 +1,88 @@
|
||||
package sdf
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"xdx.jelly/xgcl/api/common"
|
||||
)
|
||||
|
||||
type DeviceInfo struct {
|
||||
IssuerName [40]byte
|
||||
DeviceName [16]byte
|
||||
DeviceSerial [16]byte
|
||||
DeviceVersion uint32
|
||||
StandardVersion uint32
|
||||
AsymAlgAbility [2]uint32
|
||||
SymAlgAbility uint32
|
||||
HashAlgAbility uint32
|
||||
BufferSize uint32
|
||||
}
|
||||
|
||||
func (d *DeviceInfo) Size() int {
|
||||
return 40 + 16 + 16 + 4*7
|
||||
}
|
||||
|
||||
func strlen(s []byte) int {
|
||||
for i, c := range s {
|
||||
if c == 0 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (d *DeviceInfo) String() string {
|
||||
return fmt.Sprintf("IssuerName: %s\nDeviceName: %s\nDeviceSerial: %s\nDeviceVersion: 0x%08x\nStandardVersion: 0x%08x\nAsymAlgAbility: 0x%08x%08x\nSymAlgAbility 0x%08x\nHashAlgAbility 0x%08x\nBufferSize: 0x%08x",
|
||||
string(d.IssuerName[:strlen(d.IssuerName[:])]),
|
||||
string(d.DeviceName[:strlen(d.DeviceName[:])]),
|
||||
string(d.DeviceSerial[:strlen(d.DeviceSerial[:])]),
|
||||
d.DeviceVersion,
|
||||
d.StandardVersion,
|
||||
d.AsymAlgAbility[0],
|
||||
d.AsymAlgAbility[1],
|
||||
d.SymAlgAbility,
|
||||
d.HashAlgAbility,
|
||||
d.BufferSize)
|
||||
}
|
||||
|
||||
func (d *DeviceInfo) Unmarshal(data []byte) error {
|
||||
fmt.Println(data)
|
||||
if len(data) < d.Size() {
|
||||
return common.SDR_INARGERR
|
||||
}
|
||||
n := copy(d.IssuerName[:], data)
|
||||
data = data[n:]
|
||||
n = copy(d.DeviceName[:], data)
|
||||
data = data[n:]
|
||||
n = copy(d.DeviceSerial[:], data)
|
||||
data = data[n:]
|
||||
d.DeviceVersion = binary.LittleEndian.Uint32(data)
|
||||
data = data[4:]
|
||||
d.StandardVersion = binary.LittleEndian.Uint32(data)
|
||||
data = data[4:]
|
||||
d.AsymAlgAbility[0] = binary.LittleEndian.Uint32(data)
|
||||
data = data[4:]
|
||||
d.AsymAlgAbility[1] = binary.LittleEndian.Uint32(data)
|
||||
data = data[4:]
|
||||
d.SymAlgAbility = binary.LittleEndian.Uint32(data)
|
||||
data = data[4:]
|
||||
d.HashAlgAbility = binary.LittleEndian.Uint32(data)
|
||||
data = data[4:]
|
||||
d.BufferSize = binary.LittleEndian.Uint32(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
devInfo = &DeviceInfo{
|
||||
IssuerName: [40]byte{'G', 'o', 'M', 'a', 'i', 'n'},
|
||||
DeviceName: [16]byte{'G', 'C', 'L'},
|
||||
DeviceSerial: [16]byte{'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'},
|
||||
DeviceVersion: 1,
|
||||
StandardVersion: 1,
|
||||
AsymAlgAbility: [2]uint32{10000, 10000},
|
||||
SymAlgAbility: 10000,
|
||||
HashAlgAbility: 10000,
|
||||
BufferSize: 1024, // 最大随机数长度
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,4 @@
|
||||
package sdf
|
||||
|
||||
/* package sdf 是对gcl的SDF接口封装。
|
||||
*/
|
||||
@@ -0,0 +1,99 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sdf
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"hash"
|
||||
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
)
|
||||
|
||||
// Split a premaster secret in two as specified in RFC 4346, Section 5.
|
||||
func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
|
||||
s1 = secret[0 : (len(secret)+1)/2]
|
||||
s2 = secret[len(secret)/2:]
|
||||
return
|
||||
}
|
||||
|
||||
// pHash implements the P_hash function, as defined in RFC 4346, Section 5.
|
||||
func pHash(result, secret, seed []byte, hash func() hash.Hash) {
|
||||
h := hmac.New(hash, secret)
|
||||
h.Write(seed)
|
||||
a := h.Sum(nil)
|
||||
|
||||
j := 0
|
||||
for j < len(result) {
|
||||
h.Reset()
|
||||
h.Write(a)
|
||||
h.Write(seed)
|
||||
b := h.Sum(nil)
|
||||
copy(result[j:], b)
|
||||
j += len(b)
|
||||
|
||||
h.Reset()
|
||||
h.Write(a)
|
||||
a = h.Sum(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func prfTLCP(result, secret, label, seed []byte) {
|
||||
labelAndSeed := make([]byte, len(label)+len(seed))
|
||||
copy(labelAndSeed, label)
|
||||
copy(labelAndSeed[len(label):], seed)
|
||||
|
||||
pHash(result, secret, labelAndSeed, sm3.New)
|
||||
}
|
||||
|
||||
const (
|
||||
masterSecretLength = 48 // Length of a master secret in TLS 1.1.
|
||||
finishedVerifyLength = 12 // Length of verify_data in a Finished message.
|
||||
)
|
||||
|
||||
var masterSecretLabel = []byte("master secret")
|
||||
var keyExpansionLabel = []byte("key expansion")
|
||||
|
||||
// masterFromPreMasterSecret generates the master secret from the pre-master
|
||||
// secret. See RFC 5246, Section 8.1.
|
||||
func masterFromPreMasterSecretTLCP(preMasterSecret, clientRandom, serverRandom []byte) []byte {
|
||||
seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
|
||||
seed = append(seed, clientRandom...)
|
||||
seed = append(seed, serverRandom...)
|
||||
|
||||
masterSecret := make([]byte, masterSecretLength)
|
||||
prfTLCP(masterSecret, preMasterSecret, masterSecretLabel, seed)
|
||||
return masterSecret
|
||||
}
|
||||
|
||||
// keysFromMasterSecret generates the connection keys from the master
|
||||
// secret, given the lengths of the MAC key, cipher key and IV, as defined in
|
||||
// RFC 2246, Section 6.3.
|
||||
func keysFromMasterSecretTLCP(masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
|
||||
seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
|
||||
seed = append(seed, serverRandom...)
|
||||
seed = append(seed, clientRandom...)
|
||||
|
||||
n := 2*macLen + 2*keyLen + 2*ivLen
|
||||
keyMaterial := make([]byte, n)
|
||||
prfTLCP(keyMaterial, masterSecret, keyExpansionLabel, seed)
|
||||
clientMAC = keyMaterial[:macLen]
|
||||
keyMaterial = keyMaterial[macLen:]
|
||||
serverMAC = keyMaterial[:macLen]
|
||||
keyMaterial = keyMaterial[macLen:]
|
||||
clientKey = keyMaterial[:keyLen]
|
||||
keyMaterial = keyMaterial[keyLen:]
|
||||
serverKey = keyMaterial[:keyLen]
|
||||
keyMaterial = keyMaterial[keyLen:]
|
||||
clientIV = keyMaterial[:ivLen]
|
||||
keyMaterial = keyMaterial[ivLen:]
|
||||
serverIV = keyMaterial[:ivLen]
|
||||
return
|
||||
}
|
||||
|
||||
func KeysFromPreMasterSecretTLCP(preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
|
||||
|
||||
masterSecret := masterFromPreMasterSecretTLCP(preMasterSecret, clientRandom, serverRandom)
|
||||
return keysFromMasterSecretTLCP(masterSecret, clientRandom, serverRandom, macLen, keyLen, ivLen)
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package sdf
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"io"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
"golang.org/x/crypto/cryptobyte/asn1"
|
||||
"xdx.jelly/xgcl/api/common"
|
||||
)
|
||||
|
||||
func init() {
|
||||
panic("Use package xdx.jelly/xsxfv2 instead")
|
||||
}
|
||||
|
||||
// PrivateKey implements the crypto.{Signer,Decrypter} interfaces
|
||||
type PrivateKey struct {
|
||||
Sdfable
|
||||
Index uint32
|
||||
KeyType KeyType
|
||||
|
||||
publicKey interface{}
|
||||
}
|
||||
|
||||
// ?
|
||||
type PublicKey struct {
|
||||
Sdfable
|
||||
Index uint32
|
||||
KeyType KeyType
|
||||
}
|
||||
|
||||
// Public return the public key. 注意可能return nil
|
||||
func (p *PrivateKey) Public() crypto.PublicKey {
|
||||
if p.publicKey != nil {
|
||||
return p
|
||||
}
|
||||
|
||||
switch p.KeyType {
|
||||
case KeyTypeSm2Enc:
|
||||
if k, err := p.SDF_ExportEncPublicKey_ECC(p.Index); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
p.publicKey = k
|
||||
return k
|
||||
}
|
||||
case KeyTypeSm2Sign:
|
||||
if k, err := p.SDF_ExportSignPublicKey_ECC(p.Index); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
p.publicKey = k
|
||||
return k
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Sign signs digest with the private key
|
||||
// rand为nil,使用sdf接口的随机数. 有时rand也可以取如crypto/rand, 减少密码机调用,加快速度。
|
||||
// SM2:digest输入预处理结果。opts输入nil
|
||||
// RSA:TODO
|
||||
// return: ASN1 encoded signature
|
||||
func (p *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
|
||||
switch p.KeyType {
|
||||
case KeyTypeSm2Sign:
|
||||
sig, err := p.SDF_InternalSign_ECC(p.Index, digest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
||||
b.AddASN1BigInt(sig.R)
|
||||
b.AddASN1BigInt(sig.S)
|
||||
})
|
||||
return b.Bytes()
|
||||
default:
|
||||
return nil, common.SDR_NOTSUPPORT
|
||||
}
|
||||
}
|
||||
|
||||
// Decrypter implements the crypto.Decryptor interface.
|
||||
// rand为nil,使用sdf接口的随机数. 有时rand也可以取如crypto/rand, 减少密码机调用,加快速度。
|
||||
// SM2:digest输入预处理结果。opts输入nil
|
||||
// RSA:TODO
|
||||
func (p *PrivateKey) Decrypt(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) {
|
||||
switch p.KeyType {
|
||||
case KeyTypeSm2Enc:
|
||||
return nil, common.SDR_NOTSUPPORT
|
||||
|
||||
default:
|
||||
return nil, common.SDR_NOTSUPPORT
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
package sdf_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"xdx.jelly/xgcl/api/common"
|
||||
"xdx.jelly/xgcl/api/sdf"
|
||||
"xdx.jelly/xgcl/identifier"
|
||||
"xdx.jelly/xgcl/sm/sm2"
|
||||
)
|
||||
|
||||
var gsdf sdf.Sdfable
|
||||
var index uint32 = 1
|
||||
var peerIndex uint32 = 2
|
||||
|
||||
func init() {
|
||||
SDF := &sdf.SdfNoLock{}
|
||||
for idx := uint32(1); idx < 10000; idx++ {
|
||||
refKey := &common.ECCrefPrivateKey{Bits: 256}
|
||||
SDF.SDF_GenerateRandom(refKey.K[32:])
|
||||
|
||||
var err error
|
||||
err = SDF.ImportSm2KeyAtIndex(idx, sdf.KeyTypeSm2Sign, refKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = SDF.ImportSm2KeyAtIndex(idx, sdf.KeyTypeSm2Enc, refKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
for idx := uint32(0); idx < 10000; idx++ {
|
||||
SDF.GenerateKekAtIndex(idx)
|
||||
}
|
||||
|
||||
gsdf = SDF
|
||||
}
|
||||
|
||||
func TestDevInfo(t *testing.T) {
|
||||
_, err := gsdf.SDF_GetDeviceInfo()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateRandom(t *testing.T) {
|
||||
buf := make([]byte, 32)
|
||||
if n, err := gsdf.SDF_GenerateRandom(buf); err != nil || n < uint32(len(buf)) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
t.Fatalf("Generate %d random bytes, desired %d\n", n, len(buf))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
buf := make([]byte, 32)
|
||||
|
||||
sig, err := gsdf.SDF_InternalSign_ECC(index, buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = gsdf.SDF_InternalVerify_ECC(index, buf, sig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateKey_ECC(t *testing.T) {
|
||||
gsdf.SDF_OpenSession()
|
||||
defer gsdf.SDF_CloseSession()
|
||||
encKey, handle1, err := gsdf.SDF_GenerateKeyWithIPK_ECC(index, 128)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer gsdf.SDF_DestroyKey(handle1)
|
||||
|
||||
handle2, err := gsdf.SDF_ImportKeyWithISK_ECC(index, encKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer gsdf.SDF_DestroyKey(handle2)
|
||||
|
||||
var data [128]byte
|
||||
var iv [16]byte
|
||||
encData := []byte{}
|
||||
decData := []byte{}
|
||||
_, _ = gsdf.SDF_GenerateRandom(data[:])
|
||||
_, _ = gsdf.SDF_GenerateRandom(iv[:])
|
||||
|
||||
err = gsdf.SDF_Encrypt(handle1, identifier.SGDSM4CBC, append([]byte{}, iv[:]...), data[:], &encData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = gsdf.SDF_Decrypt(handle2, identifier.SGDSM4CBC, append([]byte{}, iv[:]...), encData, &decData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bytes.Compare(data[:], decData) != 0 {
|
||||
t.Fatal("Compare unequal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateKey_KEK(t *testing.T) {
|
||||
gsdf.SDF_OpenSession()
|
||||
defer gsdf.SDF_CloseSession()
|
||||
encKey, handle1, err := gsdf.SDF_GenerateKeyWithKEK(128, identifier.SGDSM4ECB, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer gsdf.SDF_DestroyKey(handle1)
|
||||
|
||||
handle2, err := gsdf.SDF_ImportKeyWithKEK(identifier.SGDSM4ECB, 0, encKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer gsdf.SDF_DestroyKey(handle2)
|
||||
|
||||
var data [128]byte
|
||||
var iv [16]byte
|
||||
encData := []byte{}
|
||||
decData := []byte{}
|
||||
_, _ = gsdf.SDF_GenerateRandom(data[:])
|
||||
_, _ = gsdf.SDF_GenerateRandom(iv[:])
|
||||
|
||||
err = gsdf.SDF_Encrypt(handle1, identifier.SGDSM4CBC, append([]byte{}, iv[:]...), data[:], &encData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = gsdf.SDF_Decrypt(handle2, identifier.SGDSM4CBC, append([]byte{}, iv[:]...), encData, &decData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bytes.Compare(data[:], decData) != 0 {
|
||||
t.Fatal("Compare unequal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExportPublicKey_ECC(t *testing.T) {
|
||||
gsdf.SDF_OpenSession()
|
||||
defer gsdf.SDF_CloseSession()
|
||||
|
||||
pk, err := gsdf.SDF_ExportSignPublicKey_ECC(index)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
e := make([]byte, 32)
|
||||
sig, err := gsdf.SDF_InternalSign_ECC(index, e)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = gsdf.SDF_ExternalVerify_ECC(identifier.SGDSM21, pk, e, sig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateKey_SSL(t *testing.T) {
|
||||
|
||||
preMasterSecret := make([]byte, 48)
|
||||
preMasterSecret[0] = 1
|
||||
preMasterSecret[1] = 1
|
||||
gsdf.SDF_GenerateRandom(preMasterSecret[2:])
|
||||
|
||||
var clientServerRandom [32 * 2]byte
|
||||
gsdf.SDF_GenerateRandom(clientServerRandom[:])
|
||||
|
||||
pucPublicKey, err := gsdf.SDF_ExportEncPublicKey_ECC(index)
|
||||
|
||||
pucKeyClientMac, phKeyHandleClientMac, pucKeyServerMac, phKeyHandleServerMac, pucKeyClientEnc, phKeyHandleClientEnc, pucKeyServerEnc, phKeyHandleServerEnc,
|
||||
clientWriteIV, serverWriteIV, err := gsdf.SDF_GenerateKeywithEPK_SSL(preMasterSecret, clientServerRandom[:32], clientServerRandom[32:], identifier.SGDSM3, identifier.SGDSM23, pucPublicKey, 128, 128, 128, 128)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
keyHandleClientMac, err := gsdf.SDF_ImportKeyWithISK_ECC(index, pucKeyClientMac)
|
||||
keyHandleServerMac, err := gsdf.SDF_ImportKeyWithISK_ECC(index, pucKeyServerMac)
|
||||
keyHandleClientEnc, err := gsdf.SDF_ImportKeyWithISK_ECC(index, pucKeyClientEnc)
|
||||
keyHandleServerEnc, err := gsdf.SDF_ImportKeyWithISK_ECC(index, pucKeyServerEnc)
|
||||
|
||||
msg := make([]byte, 128)
|
||||
gsdf.SDF_GenerateRandom(msg)
|
||||
|
||||
clientMac1, err := gsdf.SDF_CalculateMAC(keyHandleClientMac, identifier.SGDSM3, nil, msg)
|
||||
clientMac2, err := gsdf.SDF_CalculateMAC(phKeyHandleClientMac, identifier.SGDSM3, nil, msg)
|
||||
if bytes.Compare(clientMac1, clientMac2) != 0 {
|
||||
t.Fatal("client mac error")
|
||||
}
|
||||
|
||||
serverMac1, err := gsdf.SDF_CalculateMAC(keyHandleServerMac, identifier.SGDSM3, nil, msg)
|
||||
serverMac2, err := gsdf.SDF_CalculateMAC(phKeyHandleServerMac, identifier.SGDSM3, nil, msg)
|
||||
if bytes.Compare(serverMac1, serverMac2) != 0 {
|
||||
t.Fatal("server mac error")
|
||||
}
|
||||
|
||||
encMsg := make([]byte, len(msg))
|
||||
decMsg := make([]byte, len(msg))
|
||||
err = gsdf.SDF_Encrypt(keyHandleClientEnc, identifier.SGDSM4CBC, append([]byte{}, clientWriteIV...), msg, &encMsg)
|
||||
err = gsdf.SDF_Decrypt(phKeyHandleClientEnc, identifier.SGDSM4CBC, append([]byte{}, clientWriteIV...), encMsg, &decMsg)
|
||||
if bytes.Compare(msg, decMsg) != 0 {
|
||||
t.Fatal("client enc error")
|
||||
}
|
||||
|
||||
err = gsdf.SDF_Encrypt(keyHandleServerEnc, identifier.SGDSM4CBC, append([]byte{}, serverWriteIV...), msg, &encMsg)
|
||||
err = gsdf.SDF_Decrypt(phKeyHandleServerEnc, identifier.SGDSM4CBC, append([]byte{}, serverWriteIV...), encMsg, &decMsg)
|
||||
if bytes.Compare(msg, decMsg) != 0 {
|
||||
t.Fatal("server enc error")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGenerateKey_ECDHE_SSL(t *testing.T) {
|
||||
//TODO 预主密钥48字节,前两字节应该是版本号。生成46字节的协商密钥
|
||||
pucSponsorPublicKey, pucSponsorTmpPublicKey, phAgreementHandle, err := gsdf.SDF_GenerateAgreementDataWithECC(index, 46*8, sm2.GetDefaultID())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pucResponsePublicKey, pucResponseTmpPublicKey, phKeyHandle2, err := gsdf.SDF_GenerateAgreementDataAndKeyWithECC(peerIndex, 46*8, sm2.GetDefaultID(), sm2.GetDefaultID(), pucSponsorPublicKey, pucSponsorTmpPublicKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
phKeyHandle1, err := gsdf.SDF_GenerateKeyWithECC(sm2.GetDefaultID(), pucResponsePublicKey, pucResponseTmpPublicKey, phAgreementHandle)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var clientServerRandom [32 * 2]byte
|
||||
gsdf.SDF_GenerateRandom(clientServerRandom[:])
|
||||
pucClientRandom := clientServerRandom[:32]
|
||||
pucServerRandom := clientServerRandom[:32]
|
||||
|
||||
phKeyHandleClientMac1, phKeyHandleServerMac1, phKeyHandleClientEnc1, phKeyHandleServerEnc1, clientWriteIV1, serverWriteIV1, err := gsdf.SDF_GenerateKeywithECDHE_SSL(phKeyHandle1, pucClientRandom, pucServerRandom, identifier.SGDSM3, 128, 128, 128, 128)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
phKeyHandleClientMac2, phKeyHandleServerMac2, phKeyHandleClientEnc2, phKeyHandleServerEnc2, clientWriteIV2, serverWriteIV2, err := gsdf.SDF_GenerateKeywithECDHE_SSL(phKeyHandle2, pucClientRandom, pucServerRandom, identifier.SGDSM3, 128, 128, 128, 128)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
msg := make([]byte, 128)
|
||||
gsdf.SDF_GenerateRandom(msg)
|
||||
|
||||
clientMac1, err := gsdf.SDF_CalculateMAC(phKeyHandleClientMac1, identifier.SGDSM3, nil, msg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
clientMac2, err := gsdf.SDF_CalculateMAC(phKeyHandleClientMac2, identifier.SGDSM3, nil, msg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if bytes.Compare(clientMac1, clientMac2) != 0 {
|
||||
t.Fatal("client mac error")
|
||||
}
|
||||
|
||||
serverMac1, err := gsdf.SDF_CalculateMAC(phKeyHandleServerMac1, identifier.SGDSM3, nil, msg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
serverMac2, err := gsdf.SDF_CalculateMAC(phKeyHandleServerMac2, identifier.SGDSM3, nil, msg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bytes.Compare(serverMac1, serverMac2) != 0 {
|
||||
t.Fatal("server mac error")
|
||||
}
|
||||
|
||||
encMsg := make([]byte, len(msg))
|
||||
decMsg := make([]byte, len(msg))
|
||||
err = gsdf.SDF_Encrypt(phKeyHandleClientEnc1, identifier.SGDSM4CBC, clientWriteIV1, msg, &encMsg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = gsdf.SDF_Decrypt(phKeyHandleClientEnc2, identifier.SGDSM4CBC, clientWriteIV2, encMsg, &decMsg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bytes.Compare(msg, decMsg) != 0 {
|
||||
t.Fatal("client enc error")
|
||||
}
|
||||
|
||||
err = gsdf.SDF_Encrypt(phKeyHandleServerEnc1, identifier.SGDSM4CBC, serverWriteIV1, msg, &encMsg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = gsdf.SDF_Decrypt(phKeyHandleServerEnc2, identifier.SGDSM4CBC, serverWriteIV2, encMsg, &decMsg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bytes.Compare(msg, decMsg) != 0 {
|
||||
t.Fatal("server enc error")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
package sdf
|
||||
|
||||
import (
|
||||
"xdx.jelly/xgcl/rsa"
|
||||
"xdx.jelly/xgcl/sm/sm2"
|
||||
)
|
||||
|
||||
// Sdfable is the golang style of SDF interface(GB/T 36322-2018). The interface is
|
||||
// to minimum the upper applications' burden to use.
|
||||
//
|
||||
// The implement itself should be a sessionhandle.
|
||||
// So there are no need of sessionhandle in function params.
|
||||
// When New a impl. instants, it should include the device infos - IP,
|
||||
// port, connection timeout e.t.
|
||||
//
|
||||
// Its the impl's responsible to check connections to hardware
|
||||
// crypto-services.
|
||||
//
|
||||
// The params' name are keep the same with 0018/36322 for reference, though
|
||||
// the "puc" are not means "pointer to unsigned char".
|
||||
type Sdfable interface {
|
||||
StdSdfable // 标准0018接口
|
||||
ExtSdfable // 扩展接口
|
||||
SdfManager // 管理接口
|
||||
}
|
||||
|
||||
// 标准sdf接口
|
||||
type StdSdfable interface {
|
||||
// 实际上应该是OpenDevice返回一个Sdfable接口对象。实现时可以以包函数的方式实现。
|
||||
// SDF_OpenDevice() error
|
||||
// SDF_CloseDevice() error
|
||||
|
||||
// 一个Sdfable接口对象即是一个session
|
||||
SDF_OpenSession() error
|
||||
SDF_CloseSession() error
|
||||
|
||||
SDF_GetDeviceInfo() (*DeviceInfo, error)
|
||||
SDF_GetPrivateKeyAccessRight(keyIndex uint32, password []byte) error
|
||||
SDF_ReleasePrivateKeyAccessRight(keyIndex uint32) error
|
||||
|
||||
// 以随机数填充buffer。返回实际获取字节和错误。
|
||||
SDF_GenerateRandom(buffer []byte) (n uint32, err error)
|
||||
|
||||
// 6.3.1 导出RSA签名公钥
|
||||
// 描述: 导出密码设备内部存储的指定索引位置的签名公钥。
|
||||
// 备注:返回公钥只可读。不可进行更改。
|
||||
SDF_ExportSignPublicKey_RSA(uiKeyIndex uint32) (*rsa.PublicKey, error)
|
||||
|
||||
// 6.3.2 导出RSA加密公钥
|
||||
// 描述: 导出密码设备内部存储的指定索引位置的加密公钥。
|
||||
// 备注:返回公钥只可读。不可进行更改。
|
||||
SDF_ExportEncPublicKey_RSA(uiKeyIndex uint32) (*rsa.PublicKey, error)
|
||||
|
||||
// 6.3.3 产生RSA密钥对并输出
|
||||
SDF_GenerateKeyPair_RSA(uiKeyBits uint32) (*rsa.PublicKey, *rsa.PrivateKey, error)
|
||||
|
||||
// 6.3.4 生成会话密钥并用内部RSA公钥加密输出
|
||||
// 描述: 生成会话密钥并用指定索引的内部加密公钥加密输出, 同时返回密钥句柄。
|
||||
// 备注: 公钥加密数据时填充方式按照PKCS#1 v1.5的要求进行。
|
||||
SDF_GenerateKeyWithIPK_RSA(uiIPKIndex uint32, uiKeyBits uint32) (pucKey []byte, phKeyHandle interface{}, err error)
|
||||
|
||||
// 6.3.5 生成会话密钥并用外部RSA公钥加密输出
|
||||
// 描述: 生成会话密钥并用外部公钥加密输出, 同时返回密钥句柄。
|
||||
// 备注: 公钥加密数据时填充方式按照PKCS#1 v1.5的要求进行。
|
||||
SDF_GenerateKeyWithEPK_RSA(uiKeyBits uint32, pucPublicKey *rsa.PublicKey) (Key []byte, phKeyHandle interface{}, err error)
|
||||
|
||||
// 6.3.6 导入会话密钥并用内部RSA私钥解密
|
||||
// 描述: 导入会话密钥并用内部私钥解密, 同时返回密钥句柄。
|
||||
// 注:填充方式与公钥加密时相同。
|
||||
SDF_ImportKeyWithISK_RSA(uiISKIndex uint32, pucKey []byte) (phKeyHandle interface{}, err error)
|
||||
|
||||
// 6.3.7 基于RSA算法的数字信封转换
|
||||
// 描述: 将由内部加密公钥加密的会话密钥转换为由外部指定的公钥加密, 可用于数字信封转换。
|
||||
SDF_ExchangeDigitEnvelopeBaseOnRSA(uiKeyIndex uint32, pucPublicKey *rsa.PublicKey, pucDEInput []byte) (pucDEOutput []byte, err error)
|
||||
|
||||
// 6.3.8 导出ECC签名公钥
|
||||
SDF_ExportSignPublicKey_ECC(uiKeyIndex uint32) (*sm2.PublicKey, error)
|
||||
|
||||
// 6.3.9 导出ECC加密公钥
|
||||
// 描述: 导出密码设备内部存储的指定索引位置的加密公钥。
|
||||
SDF_ExportEncPublicKey_ECC(uiKeyIndex uint32) (*sm2.PublicKey, error)
|
||||
|
||||
// 6.3.10 产生ECC密钥对并输出
|
||||
// 描述: 请求密码设备产生指定类型和模长的ECC密钥对。
|
||||
SDF_GenerateKeyPair_ECC(uiAlgID uint32, uiKeyBits uint32) (*sm2.PublicKey, *sm2.PrivateKey, error)
|
||||
|
||||
// 6.3.11 生成会话密钥并用内部ECC公钥加密输出
|
||||
// 描述: 生成会话密钥并用指定索引的内部ECC加密公钥加密输出, 同时返回密钥句柄。
|
||||
SDF_GenerateKeyWithIPK_ECC(uiIPKIndex uint32, uiKeyBits uint32) (pucKey *sm2.Cipher, phKeyHandle interface{}, err error)
|
||||
|
||||
// 6.3.12 生成会话密钥并用外部ECC公钥加密输出
|
||||
// 描述: 生成会话密钥并用外部ECC公钥加密输出, 同时返回密钥句柄。
|
||||
SDF_GenerateKeyWithEPK_ECC(uiKeyBits uint32, uiAlgID uint32, pucPublicKey *sm2.PublicKey) (pucKey *sm2.Cipher, phKeyHandle interface{}, err error)
|
||||
|
||||
// 6.3.13 导入会话密钥并用内部ECC私钥解密
|
||||
// 描述: 导入会话密钥并用内部ECC加密私钥解密, 同时返回密钥句柄。
|
||||
SDF_ImportKeyWithISK_ECC(uiISKIndex uint32, pucKey *sm2.Cipher) (phKeyHandle interface{}, err error)
|
||||
|
||||
// 6.3.14 生成密钥协商参数并输出
|
||||
// 描述: 使用ECC密钥协商算法, 为计算会话密钥而产生协商参数, 同时返回指定索引位置的ECC公钥、临时ECC密钥对的公钥及协商句柄。
|
||||
SDF_GenerateAgreementDataWithECC(uiISKIndex uint32, uiKeyBits uint32, pucSponsorID []byte) (pucSponsorPublicKey *sm2.PublicKey, pucSponsorTmpPublicKey *sm2.PublicKey, phAgreementHandle interface{}, err error)
|
||||
|
||||
// 6.3.15 计算会话密钥
|
||||
// 描述: 使用ECC密钥协商算法, 使用自身协商句柄和响应方的协商参数计算会话密钥, 同时返回会话密钥句柄。
|
||||
// 备注: 协商的发起方获得响应方的协商参数后调用本函数, 计算会话密钥。使用SM2算法计算会话密钥的过程见GM/T 0009。
|
||||
SDF_GenerateKeyWithECC(pucResponseID []byte, pucResponsePublicKey *sm2.PublicKey, pucResponseTmpPublicKey *sm2.PublicKey, hAgreementHandle interface{}) (phKeyHandle interface{}, err error)
|
||||
|
||||
// 6.3.16 产生协商数据并计算会话密钥
|
||||
// 描述: 使用ECC密钥协商算法, 产生协商参数并计算会话密钥, 同时返回产生的协商参数和密钥句柄。
|
||||
SDF_GenerateAgreementDataAndKeyWithECC(uiISKIndex uint32, uiKeyBits uint32, pucResponseID []byte, pucSponsorID []byte, pucSponsorPublicKey, pucSponsorTmpPublicKey *sm2.PublicKey) (pucResponsePublicKey *sm2.PublicKey, pucResponseTmpPublicKey *sm2.PublicKey, phKeyHandle interface{}, err error)
|
||||
|
||||
// 6.3.17 基于ECC算法的数字信封转换
|
||||
// 描述: 将由内部加密公钥加密的会话密钥转换为由外部指定的公钥加密, 可用于数字信封转换。
|
||||
SDF_ExchangeDigitEnvelopeBaseOnECC(uiKeyIndex uint32, uiAlgID uint32, pucPublicKey *sm2.PublicKey,
|
||||
pucEncDataIn *sm2.Cipher) (pucEncDataOut *sm2.Cipher, err error)
|
||||
|
||||
// 6.3.18 生成会话密钥并用密钥加密密钥加密输出
|
||||
// 描述: 生成会话密钥并用密钥加密密钥加密输出, 同时返回密钥句柄。
|
||||
// 备注: 加密模式使用ECB模式。
|
||||
SDF_GenerateKeyWithKEK(uiKeyBits uint32, uiAlgID uint32, uiKEKIndex uint32) (pucKey []byte, phKeyHandle interface{}, err error)
|
||||
|
||||
// 6.3.19 导入会话密钥并用密钥加密密钥解密
|
||||
// 描述: 导入会话密钥并用密钥加密密钥解密, 同时返回会话密钥句柄。
|
||||
// 备注: 加密模式使用ECB模式。
|
||||
SDF_ImportKeyWithKEK(uiAlgID uint32, uiKEKIndex uint32, pucKey []byte) (phKeyHandle interface{}, err error)
|
||||
|
||||
// 6.3.20 计算IKE工作密钥
|
||||
// 描述: 使用IKE一阶段(主模式)交换得到的密钥计算参数计算IKE会话密钥, 同时返回会话密钥句柄。
|
||||
// 备注: IKE一阶段(主模式)消息3和消息4交互完成后, 参与通信的双方调用本函数,
|
||||
// 计算后续会话密钥SKEYID_d, SKEYID_a, SKEYID_e。IKE一阶段(主模式)计算IKE会话密钥的过程见GM/T 0022。
|
||||
// 输入的密钥参数按顺序为Ni_b, Nr_b, CKY_I, CKY_R,返回的密钥句柄按顺序为SKEYID_d,SKEYID_a,SKEYID_e
|
||||
SDF_GenerateKeywithIKE(pucSponsorNonce []byte, pucResponseNonce []byte, pucSponsorCookie []byte, pucResponseCookie []byte, uiPrfAlgID uint32, uiKeyBitsD, uiKeyBitsA, uiKeyBitsE uint32) (phKeyHandleD interface{}, phKeyHandleA interface{}, phKeyHandleE interface{}, err error)
|
||||
|
||||
// 6.3.22 计算IKE工作密钥并用外部ECC公钥加密输出
|
||||
// 描述: 使用IKE一阶段(主模式)交换得到的密钥计算参数计算IKE工作密钥,并用外部
|
||||
// ECC公钥加密输出,同时返回工作密钥句柄。
|
||||
// 备注: IKE一阶段(主模式)消息3和消息4交互完成后, 参与通信的双方调用本函数,
|
||||
// 计算后续会话密钥SKEYID_d, SKEYID_a, SKEYID_e。IKE一阶段(主模式)计算IKE会话密钥的过程见GM/T 0022。
|
||||
// 输入的密钥参数按顺序为Ni_b, Nr_b, CKY_I, CKY_R,返回的密钥句柄按顺序为SKEYID_d,SKEYID_a,SKEYID_e
|
||||
SDF_GenerateKeywithEPK_IKE(pucSponsorNonce []byte, pucResponseNonce []byte, pucSponsorCookie []byte, pucResponseCookie []byte, uiPrfAlgID, uiEccAlgID uint32, pucPublicKey sm2.PublicKey, uiKeyBitsD, uiKeyBitsA, uiKeyBitsE uint32) (pucKeyD *sm2.Cipher, phKeyHandleD interface{}, pucKeyA *sm2.Cipher, phKeyHandleA interface{}, pucKeyE *sm2.Cipher, phKeyHandleE interface{}, err error)
|
||||
|
||||
// 6.3.23 计算IPSEC会话密钥
|
||||
// 描述: 使用IKE二阶段(快速模式)交换得到的密钥计算参数计算IPSEC会话密钥, 同时返回会话密钥句柄。
|
||||
// 备注: IKE二阶段(快速模式)消息交互完成后, 参与通信的双方调用本函数, 计算IPSEC会话密钥, 包括用于加密的会话密钥和用于完整性校验的会话密钥。IKE二阶段(快速模式)计算IPSEC会话密钥的过程见GM/T 0022。本函数需在6.3.20计算IKE会话密钥函数调用之后调用, 并将该函数返回的密钥句柄之一(SKEYID_d)作为输入。
|
||||
SDF_GenerateKeywithIPSEC(
|
||||
pucProtocolID []byte,
|
||||
pucSpi []byte,
|
||||
pucSponsorNonce []byte,
|
||||
pucResponseNonce []byte,
|
||||
hKeyHandle interface{},
|
||||
uiPrfAlgID uint32,
|
||||
uiKeyBitsEnc, uiKeyBitsMac uint32,
|
||||
) (phKeyHandleEnc interface{}, phKeyHandleMac interface{}, err error)
|
||||
|
||||
// 6.3.24 计算IPSEC会话密钥并用外部ECC公钥加密输出
|
||||
// 注:IKE 二阶段(快速模式)消息交互完成后,本函数由参与通信的双方各自调用,计算IPSEC 会话密钥,包括用于
|
||||
// 加密的会话密钥和用于完整性校验的会话密钥。IKE 二阶段(快速模式)计算IPSEC 会话密钥的过程参见
|
||||
// GM/T0022,输入的密钥参数按顺序为protocol、SPI、Ni_b、Nr_b,返回的密钥密文和密钥句柄按顺序为加密密
|
||||
// 钥和杂凑密钥(用于完整性校验)。本函数在6.3.21计算IKE 工作密钥函数调用之后调用,该函数返回的密钥
|
||||
// 句柄之一(SKEYID_d)作为本函数输入。
|
||||
SDF_GenerateKeywithEPK_IPSEC(
|
||||
pucProtocolID []byte,
|
||||
pucSpi []byte,
|
||||
pucSponsorNonce []byte,
|
||||
pucResponseNonce []byte,
|
||||
hKeyHandle interface{},
|
||||
uiPrfAlgID uint32,
|
||||
uiEccAlgID uint32,
|
||||
pucPublicKey *sm2.PublicKey,
|
||||
uiKeyBitsEnc, uiKeyBitsMac uint32,
|
||||
) (pucKeyEnc *sm2.Cipher, phKeyHandleEnc interface{}, pucKeyMac *sm2.Cipher, phKeyHandleMac interface{}, err error)
|
||||
|
||||
// 6.3.25 计算SSL工作密钥
|
||||
// 描述: 使用SSL握手协议得到的密钥计算参数计算SSL会话密钥, 同时返回会话密钥句柄。
|
||||
// 备注:
|
||||
// SSL握手协议消息交互完成后, 参与通信的双方调用本函数, 计算SSL记录层协议的会话密钥client_write_MAC_secret, server_write_MAC_secret, client_write_ key, server_write_key。SSL计算会话密钥的过程见GM/T 0024。
|
||||
// 备注:与标准有不同,这里增加了返回pucClientIV, pucServerIV
|
||||
SDF_GenerateKeywithSSL(
|
||||
pucKeyPremaster, pucClientRandom, pucServerRandom []byte,
|
||||
uiPrfAlgID uint32,
|
||||
uiKeyBitsClientMac, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc uint32,
|
||||
) (phKeyHandleClientMac, phKeyHandleServerMac, phKeyHandleClientEnc, phKeyHandleServerEnc interface{}, pucClientIV, pucServerIV []byte, err error)
|
||||
|
||||
// 6.3.26 计算SSL工作密钥并用外部ECC公钥加密输出
|
||||
SDF_GenerateKeywithEPK_SSL(pucKeyPremaster, pucClientRandom, pucServerRandom []byte, uiPrfAlgID uint32, uiEccAlgID uint32, pucPublicKey *sm2.PublicKey, uiKeyBitsClientMac, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc uint32) (pucKeyClientMac *sm2.Cipher, phKeyHandleClientMac interface{}, pucKeyServerMac *sm2.Cipher, phKeyHandleServerMac interface{}, pucKeyClientEnc *sm2.Cipher, phKeyHandleClientEnc interface{}, pucKeyServerEnc *sm2.Cipher, phKeyHandleServerEnc interface{}, pucClientIV, pucServerIV []byte, err error)
|
||||
|
||||
// 6.3.27 计算SSL工作密钥(ECDHE)
|
||||
// 描述: 使用SSL握手协议得到的密钥计算参数计算SSL工作密钥,同时返回工作密钥句柄。
|
||||
// 备注:这里的预主密钥为SM2密钥交换得到的密钥句柄。
|
||||
SDF_GenerateKeywithECDHE_SSL(
|
||||
phKeyHandlePremaster interface{},
|
||||
pucClientRandom, pucServerRandom []byte,
|
||||
uiPrfAlgID uint32,
|
||||
uiKeyBitsClientMac, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc uint32,
|
||||
) (phKeyHandleClientMac, phKeyHandleServerMac, phKeyHandleClientEnc, phKeyHandleServerEnc interface{}, pucClientIV, pucServerIV []byte, err error)
|
||||
|
||||
// 6.3.28 计算SSL工作密钥并用外部ECC公钥加密输出
|
||||
// 描述: 使用SSL握手协议得到的密钥计算参数计算SSL工作密钥,同时返回工作密钥句柄。
|
||||
// 备注:这里的预主密钥为SM2密钥交换得到的密钥句柄。
|
||||
SDF_GenerateKeywithEPK_ECDHE_SSL(phKeyHandlePremaster interface{}, pucClientRandom, pucServerRandom []byte, uiPrfAlgID uint32, uiEccAlgID uint32, pucPublicKey *sm2.PublicKey, uiKeyBitsClientMac, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc uint32) (pucKeyClientMac *sm2.Cipher, phKeyHandleClientMac interface{}, pucKeyServerMac *sm2.Cipher, phKeyHandleServerMac interface{}, pucKeyClientEnc *sm2.Cipher, phKeyHandleClientEnc interface{}, pucKeyServerEnc *sm2.Cipher, phKeyHandleServerEnc interface{}, pucClientIV, pucServerIV []byte, err error)
|
||||
|
||||
// 6.3.29 销毁会话密钥
|
||||
// 描述: 销毁会话密钥, 并释放为密钥句柄分配的内存等资源。
|
||||
// 备注: 在对称算法运算完成后, 应调用本函数销毁会话密钥。
|
||||
SDF_DestroyKey(hKeyHandle interface{}) error
|
||||
|
||||
// 6.4 非对称算法运算类函数
|
||||
// 6.4.2 外部公钥RSA运算
|
||||
// 描述: 指定使用外部公钥对数据进行运算。
|
||||
// 备注1: 数据格式由应用层封装。
|
||||
// 备注2:一般非对称运算加密密钥,因此输出为内部分配内存。
|
||||
SDF_ExternalPublicKeyOperation_RSA(pucPublicKey *rsa.PublicKey, pucDataInput []byte) (pucDataOutput []byte, err error)
|
||||
|
||||
// 6.4.3 内部公钥RSA运算
|
||||
// 描述: 使用内部指定索引的公钥对数据进行运算。
|
||||
// 备注: 索引范围仅限于内部签名密钥对, 数据格式由应用层封装。
|
||||
SDF_DecryptPublicKeyOperation_RSA(uiKeyIndex uint32, pucDataInput []byte) (pucDataOutput []byte, err error)
|
||||
|
||||
// 6.4.4 内部私钥RSA运算
|
||||
// 描述: 使用内部指定索引的私钥对数据进行运算。
|
||||
// 备注: 索引范围仅限于内部签名密钥对, 数据格式由应用层封装。
|
||||
SDF_InternalPrivateKeyOperation_RSA(
|
||||
uiKeyIndex uint32,
|
||||
pucDataInput []byte) (pucDataOutput []byte, err error)
|
||||
|
||||
// 6.4.5 外部密钥ECC验证
|
||||
// 描述: 使用外部ECC公钥对ECC签名值进行验证运算。
|
||||
// 备注: 输入数据为待签数据的杂凑值。当使用SM2算法时, 该输入数据为待签数据经过SM2签名预处理的结果, 预处理过程见GM/T 0009。
|
||||
SDF_ExternalVerify_ECC(
|
||||
uiAlgID uint32,
|
||||
pucPublicKey *sm2.PublicKey,
|
||||
pucDataInput []byte,
|
||||
pucSignature *sm2.Signature) (err error)
|
||||
|
||||
// GMT 0018-2012 有,但36322没有
|
||||
SDF_ExternalSign_ECC(uiAlgID uint32, pucPrivateKey *sm2.PrivateKey, pucData []byte) (*sm2.Signature, error)
|
||||
|
||||
// 6.4.6 内部密钥ECC签名
|
||||
// 描述: 使用内部ECC私钥对数据进行签名运算。
|
||||
// 备注: 输入数据为待签数据的杂凑值。当使用SM2算法时, 该输入数据为待签数据经过SM2签名预处理的结果, 预处理过程见GM/T 0009。
|
||||
SDF_InternalSign_ECC(uiISKIndex uint32, pucData []byte) (pucSignature *sm2.Signature, err error)
|
||||
|
||||
// 6.4.7 内部密钥ECC验证
|
||||
// 描述: 使用内部ECC公钥对ECC签名值进行验证运算。
|
||||
// 备注: 输入数据为待签数据的杂凑值。当使用SM2算法时, 该输入数据为待签数据经过SM2签名预处理的结果, 预处理过程见GM/T 0009。
|
||||
SDF_InternalVerify_ECC(
|
||||
uiISKIndex uint32,
|
||||
pucData []byte,
|
||||
pucSignature *sm2.Signature) (err error)
|
||||
|
||||
// 6.4.8 外部密钥ECC公钥加密
|
||||
// 描述: 使用外部ECC公钥对数据进行加密运算。
|
||||
SDF_ExternalEncrypt_ECC(
|
||||
uiAlgID uint32,
|
||||
pucPublicKey *sm2.PublicKey,
|
||||
pucData []byte) (pucEncData *sm2.Cipher, err error)
|
||||
|
||||
// 外部ECC私钥解密,GMT0018有,36322没有。
|
||||
SDF_ExternalDecrypt_ECC(uiAlgID uint32, pucPrivateKey *sm2.PrivateKey, pucEncData *sm2.Cipher) (pucData []byte, err error)
|
||||
|
||||
// 6.5 对称算法运算类函数
|
||||
// 对称算法运算类函数包括以下具体函数, 各函数返回值见附录A函数返回代码定义:
|
||||
// a) 对称加密:Encrypt
|
||||
// b) 对称解密:Decrypt
|
||||
// c) 计算MAC:CalculateMAC
|
||||
|
||||
// 6.5.1 对称加密
|
||||
// 描述: 使用指定的密钥句柄和IV对数据进行对称加密运算
|
||||
// 备注1: 此函数不对数据进行填充处理, 输入的数据必须是指定算法分组长度的整数倍。
|
||||
// 备注2: 为避免内存分配,pucEncData提前分配好足够的空间。pucEncData如果空间不够,会重分配内存
|
||||
// 备注3: pucIV-输入输出
|
||||
SDF_Encrypt(hKeyHandle interface{}, uiAlgID uint32, pucIV []byte, pucData []byte, pucEncData *[]byte) (err error)
|
||||
|
||||
// 6.5.2 对称解密
|
||||
// 描述: 使用指定句柄和IV对数据进行对称解密运算。
|
||||
// 备注1: 此函数不对数据进行填充处理, 输入的数据必须是指定算法分组长度的整数倍。
|
||||
// 备注2: pucIV和pucData同对称加密
|
||||
SDF_Decrypt(hKeyHandle interface{}, uiAlgID uint32, pucIV []byte, pucEncData []byte, pucData *[]byte) (err error)
|
||||
|
||||
// 6.5.3 计算MAC
|
||||
// 描述: 使用指定的密钥句柄和IV对数据进行MAC运算。
|
||||
// uiAlgID的取值为:
|
||||
// - identifier.SGD_SM3, 计算HMAC_SM3, 忽略pucIV
|
||||
// - identifier.SGD_SM1_MAC, 计算SM1_CBCMAC
|
||||
// - identifier.SGD_SM4_MAC, 计算SM4_CBCMAC
|
||||
// 备注:CBCMac不对数据进行分包处理, 多包数据MAC运算由IV控制最后的MAC值。
|
||||
SDF_CalculateMAC(hKeyHandle interface{}, uiAlgID uint32, pucIV []byte, pucData []byte) (pucMAC []byte, err error)
|
||||
|
||||
// 6.6 杂凑运算类函数
|
||||
// 备注:0018中杂凑运算与hSessionHandle相关联。
|
||||
// 6.6.2 杂凑运算初始化
|
||||
// 描述: 三步式数据杂凑运算第一步。
|
||||
// 备注: uiIDLength非零且uiAlgID为SGD_SM3时, 函数执行SM2的预处理操作。计算过程见GM/T 0009。
|
||||
SDF_HashInit(uiAlgID uint32, pucPublicKey *sm2.PublicKey, pucID []byte) (err error)
|
||||
|
||||
// 6.6.3 多包杂凑运算
|
||||
// 描述: 三步式运算第二步, 对输入的明文进行杂凑运算。
|
||||
SDF_HashUpdate(pucData []byte) (err error)
|
||||
|
||||
// 6.6.4 杂凑运算结束
|
||||
SDF_HashFinal() (pucHash []byte, err error)
|
||||
|
||||
// 6.7 用户文件操作类函数
|
||||
// 用户文件操作类函数包括以下具体函数, 各函数返回值见附录A函数返回代码定义:
|
||||
// a) 创建文件 CreateFile
|
||||
// b) 读取文件:ReadFile
|
||||
// c) 写文件:WriteFile
|
||||
// d) 删除文件:DeleteFile
|
||||
|
||||
// 6.7.2 创建文件
|
||||
// 描述: 在密码设备内部创建用于存储用户数据的文件。
|
||||
SDF_CreateFile(pucFileName string, uiFileSize uint32) error
|
||||
|
||||
// 6.7.3 读取文件
|
||||
// 描述: 读取在密码设备内部存储用户数据的文件的内容。
|
||||
// 备注: 读取文件内容至pucBuffer,返回读取字节数。
|
||||
// 当err != nil时,有可能n>0. 例如err = io.EOF时,仍可能读取到一定字节数。
|
||||
SDF_ReadFile(pucFileName string, uiOffset uint32, pucBuffer []byte) (n uint32, err error)
|
||||
|
||||
// 6.7.3 写文件
|
||||
// 描述: 向密码设备内部存储用户数据的文件中写入内容。
|
||||
SDF_WriteFile(pucFileName string, uiOffset uint32, pucBuffer []byte) error
|
||||
|
||||
// 6.7.4 删除文件
|
||||
// 描述: 删除指定文件名的密码设备内部存储用户数据的文件。
|
||||
SDF_DeleteFile(pucFileName string) error
|
||||
}
|
||||
|
||||
// sdf 的扩展接口
|
||||
type ExtSdfable interface {
|
||||
|
||||
// 内部sm2私钥解密
|
||||
SDFEXT_InternalDecryptECC(uiKeyIndex uint32, pucEncData *sm2.Cipher) (pucData []byte, err error)
|
||||
|
||||
// 6.3.14 生成密钥协商参数并输出-这个与标准接口一致
|
||||
// 描述: 使用ECC密钥协商算法, 为计算会话密钥而产生协商参数, 同时返回指定索引位置的ECC公钥、临时ECC密钥对的公钥及协商句柄。
|
||||
SDFEXT_GenerateAgreementDataWithECC(uiISKIndex uint32, uiKeyBits uint32, pucSponsorID []byte) (pucSponsorPublicKey *sm2.PublicKey, pucSponsorTmpPublicKey *sm2.PublicKey, phAgreementHandle interface{}, err error)
|
||||
|
||||
// 6.3.15 计算会话密钥变体
|
||||
// 描述: 使用ECC密钥协商算法, 使用自身协商句柄和响应方的协商参数计算会话密钥, 同时返回会话密钥。
|
||||
// 备注: 协商的发起方获得响应方的协商参数后调用本函数, 计算会话密钥。使用SM2算法计算会话密钥的过程见GM/T 0009。
|
||||
SDFEXT_GenerateKeyWithECC(pucResponseID []byte, pucResponsePublicKey *sm2.PublicKey, pucResponseTmpPublicKey *sm2.PublicKey, hAgreementHandle interface{}) (agreementKey []byte, err error)
|
||||
|
||||
// 6.3.16 产生协商数据并计算会话密钥
|
||||
// 描述: 使用ECC密钥协商算法, 产生协商参数并计算会话密钥, 同时返回产生的协商参数和密钥。
|
||||
SDFEXT_GenerateAgreementDataAndKeyWithECC(uiISKIndex uint32, uiKeyBits uint32, pucResponseID []byte, pucSponsorID []byte, pucSponsorPublicKey, pucSponsorTmpPublicKey *sm2.PublicKey) (pucResponsePublicKey *sm2.PublicKey, pucResponseTmpPublicKey *sm2.PublicKey, agreementKey []byte, err error)
|
||||
}
|
||||
|
||||
type SdfManager interface {
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
package sdf
|
||||
|
||||
import "sync"
|
||||
|
||||
// SdfWithLock 带锁的SDFable实现。
|
||||
// GCL作为软算法实例,应看做是一个device。需要进行加锁同步,可多线程共用一个实例。
|
||||
type SdfWithLock struct {
|
||||
sdflocked SdfNoLock // 先加锁,再调用sdflocked.xx
|
||||
mu sync.RWMutex
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
package sdf
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/pbkd"
|
||||
"xdx.jelly/xgcl/sm/sm2"
|
||||
"xdx.jelly/xgcl/sm/sm4"
|
||||
)
|
||||
|
||||
/*
|
||||
Example of snapshot:
|
||||
{
|
||||
"keys":[
|
||||
{
|
||||
"type": "Sm2SignKey",
|
||||
"url": "sm2sign/12",
|
||||
"material": ["base64(d)", "base64(04||x||y)"]
|
||||
},
|
||||
{
|
||||
"type": "Sm2SignKey",
|
||||
"url": "sm2enc/12",
|
||||
"material": ["base64(d)", "base64(04||x||y)"]
|
||||
},
|
||||
{
|
||||
"type": "BlockKey",
|
||||
"url": "kek/0",
|
||||
"material": ["base64(key)"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
*/
|
||||
type KeyMaterial struct {
|
||||
Type string `json:"type"`
|
||||
Url string `json:"url"`
|
||||
Nonces [][]byte `json:"nonces"` // coresponding to each Material, with add Url
|
||||
Materials [][]byte `json:"materials"`
|
||||
}
|
||||
|
||||
type EncParam struct {
|
||||
Algo string `json:"algo"` // only "sm4_gcm" are supported
|
||||
Salt []byte `json:"salt"`
|
||||
Count uint32 `json:"count"`
|
||||
}
|
||||
|
||||
type Snapshot struct {
|
||||
Time time.Time `json:"time"`
|
||||
Info string `json:"info"`
|
||||
Enc bool `json:"enc"`
|
||||
EncParam *EncParam `json:"encParam"`
|
||||
Keys []*KeyMaterial `json:"keys"`
|
||||
}
|
||||
|
||||
func (s *SdfNoLock) Snapshot(enc bool, password []byte, count int) (*Snapshot, error) {
|
||||
|
||||
snapshot := &Snapshot{
|
||||
Time: time.Now(),
|
||||
Enc: enc,
|
||||
Keys: make([]*KeyMaterial, 0),
|
||||
}
|
||||
var aead cipher.AEAD
|
||||
var nonces [][]byte
|
||||
|
||||
if enc {
|
||||
var salt []byte
|
||||
var err error
|
||||
var n uint32
|
||||
salt = make([]byte, 16)
|
||||
if n, err = s.SDF_GenerateRandom(salt); err != nil || n != uint32(len(salt)) {
|
||||
return nil, err
|
||||
}
|
||||
var encryptionKey []byte
|
||||
if encryptionKey, err = pbkd.PbkdfWithHmacSm3(password, salt, count, sm4.BlockSize); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if aead, err = sm4.NewGCM(encryptionKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonces = [][]byte{
|
||||
make([]byte, aead.NonceSize()),
|
||||
make([]byte, aead.NonceSize()),
|
||||
}
|
||||
|
||||
snapshot.EncParam = &EncParam{
|
||||
Algo: "sm4_gcm",
|
||||
Salt: salt,
|
||||
Count: uint32(count),
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range s.Sm2Key {
|
||||
if v.signKey != nil {
|
||||
sk := v.signKey.Bytes()
|
||||
pk := v.signKey.PublicKey.Bytes()
|
||||
url := fmt.Sprintf("sm2sign/%d", k)
|
||||
thisNonces := nonces
|
||||
if aead != nil {
|
||||
s.SDF_GenerateRandom(nonces[0])
|
||||
s.SDF_GenerateRandom(nonces[1])
|
||||
thisNonces = [][]byte{
|
||||
append([]byte{}, nonces[0]...),
|
||||
append([]byte{}, nonces[1]...),
|
||||
}
|
||||
sk = aead.Seal(sk[:0], nonces[0], sk, []byte(url))
|
||||
pk = aead.Seal(pk[:0], nonces[1], pk, []byte(url))
|
||||
}
|
||||
km := &KeyMaterial{
|
||||
Type: KeyTypeSm2Sign.String(),
|
||||
Url: url,
|
||||
Nonces: thisNonces,
|
||||
Materials: [][]byte{sk, pk},
|
||||
}
|
||||
snapshot.Keys = append(snapshot.Keys, km)
|
||||
}
|
||||
|
||||
if v.encKey != nil {
|
||||
sk := v.encKey.Bytes()
|
||||
pk := v.encKey.PublicKey.Bytes()
|
||||
url := fmt.Sprintf("sm2enc/%d", k)
|
||||
thisNonces := nonces
|
||||
if aead != nil {
|
||||
s.SDF_GenerateRandom(nonces[0])
|
||||
s.SDF_GenerateRandom(nonces[1])
|
||||
thisNonces = [][]byte{
|
||||
append([]byte{}, nonces[0]...),
|
||||
append([]byte{}, nonces[1]...),
|
||||
}
|
||||
sk = aead.Seal(sk[:0], nonces[0], sk, []byte(url))
|
||||
pk = aead.Seal(pk[:0], nonces[1], pk, []byte(url))
|
||||
}
|
||||
km := &KeyMaterial{
|
||||
Type: KeyTypeSm2Enc.String(),
|
||||
Url: url,
|
||||
Nonces: thisNonces,
|
||||
Materials: [][]byte{sk, pk},
|
||||
}
|
||||
snapshot.Keys = append(snapshot.Keys, km)
|
||||
}
|
||||
}
|
||||
for k, v := range s.SymKey {
|
||||
key := make([]byte, len(v.key), len(v.key)+16)
|
||||
url := fmt.Sprintf("kek/%d", k)
|
||||
thisNonces := nonces
|
||||
copy(key, v.key)
|
||||
if aead != nil {
|
||||
s.SDF_GenerateRandom(nonces[0])
|
||||
thisNonces = [][]byte{
|
||||
append([]byte{}, nonces[0]...),
|
||||
}
|
||||
key = aead.Seal(key[:0], nonces[0], key, []byte(url))
|
||||
}
|
||||
|
||||
km := &KeyMaterial{
|
||||
Type: v.keyType.String(),
|
||||
Url: url,
|
||||
Nonces: thisNonces,
|
||||
Materials: [][]byte{key},
|
||||
}
|
||||
snapshot.Keys = append(snapshot.Keys, km)
|
||||
}
|
||||
|
||||
return snapshot, nil
|
||||
}
|
||||
|
||||
func (s *SdfNoLock) Restore(ss *Snapshot, password []byte) error {
|
||||
var sdf = &SdfNoLock{
|
||||
RsaKey: make(map[uint32]*RsaKey),
|
||||
Sm2Key: make(map[uint32]*Sm2Key),
|
||||
SymKey: make(map[uint32]*SymKey),
|
||||
}
|
||||
var aead cipher.AEAD
|
||||
var err error
|
||||
if ss.Enc {
|
||||
var encryptionKey []byte
|
||||
if encryptionKey, err = pbkd.PbkdfWithHmacSm3([]byte(password), ss.EncParam.Salt, int(ss.EncParam.Count), sm4.BlockSize); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if aead, err = sm4.NewGCM(encryptionKey); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, k := range ss.Keys {
|
||||
if k == nil {
|
||||
return fmt.Errorf("nil key")
|
||||
}
|
||||
switch GetKeyType(k.Type) {
|
||||
case KeyTypeBlock:
|
||||
if len(k.Materials) != 1 || len(k.Nonces) != len(k.Materials) {
|
||||
return fmt.Errorf("key material error")
|
||||
}
|
||||
key := k.Materials[0]
|
||||
if aead != nil {
|
||||
key, err = aead.Open(nil, k.Nonces[0], key, []byte(k.Url))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
urlSplits := strings.Split(k.Url, "/")
|
||||
if len(urlSplits) != 2 {
|
||||
return fmt.Errorf("key url error")
|
||||
}
|
||||
if strings.TrimSpace(urlSplits[0]) != "kek" {
|
||||
return fmt.Errorf("key url error")
|
||||
}
|
||||
index, err := strconv.Atoi(urlSplits[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("key url error")
|
||||
} else {
|
||||
sdf.SymKey[uint32(index)] = &SymKey{
|
||||
keyType: KeyTypeBlock,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
case KeyTypeSm2Sign:
|
||||
if len(k.Materials) != 2 || len(k.Nonces) != len(k.Materials) {
|
||||
return fmt.Errorf("key material error")
|
||||
}
|
||||
sk := k.Materials[0]
|
||||
pk := k.Materials[1]
|
||||
if aead != nil {
|
||||
sk, err = aead.Open(nil, k.Nonces[0], sk, []byte(k.Url))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pk, err = aead.Open(nil, k.Nonces[1], pk, []byte(k.Url))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
urlSplits := strings.Split(k.Url, "/")
|
||||
if len(urlSplits) != 2 {
|
||||
return fmt.Errorf("key url error")
|
||||
}
|
||||
if strings.TrimSpace(urlSplits[0]) != "sm2sign" {
|
||||
return fmt.Errorf("key url error")
|
||||
}
|
||||
index, err := strconv.Atoi(urlSplits[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("key url error")
|
||||
} else {
|
||||
sm2PrivateKey := &sm2.PrivateKey{
|
||||
D: new(big.Int).SetBytes(sk),
|
||||
}
|
||||
sm2PrivateKey.PublicKey.Curve = sm2.Curve()
|
||||
sm2PrivateKey.PublicKey.X = new(big.Int).SetBytes(pk[:sm2.ByteSize()])
|
||||
sm2PrivateKey.PublicKey.Y = new(big.Int).SetBytes(pk[sm2.ByteSize():])
|
||||
|
||||
if _, ok := sdf.Sm2Key[uint32(index)]; !ok {
|
||||
sdf.Sm2Key[uint32(index)] = &Sm2Key{}
|
||||
}
|
||||
sdf.Sm2Key[uint32(index)].signKey = sm2PrivateKey
|
||||
}
|
||||
|
||||
case KeyTypeSm2Enc:
|
||||
if len(k.Materials) != 2 || len(k.Nonces) != len(k.Materials) {
|
||||
return fmt.Errorf("key material error")
|
||||
}
|
||||
sk := k.Materials[0]
|
||||
pk := k.Materials[1]
|
||||
if aead != nil {
|
||||
sk, err = aead.Open(nil, k.Nonces[0], sk, []byte(k.Url))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pk, err = aead.Open(nil, k.Nonces[1], pk, []byte(k.Url))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
urlSplits := strings.Split(k.Url, "/")
|
||||
if len(urlSplits) != 2 {
|
||||
return fmt.Errorf("key url error")
|
||||
}
|
||||
if strings.TrimSpace(urlSplits[0]) != "sm2enc" {
|
||||
return fmt.Errorf("key url error")
|
||||
}
|
||||
index, err := strconv.Atoi(urlSplits[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("key url error")
|
||||
} else {
|
||||
sm2PrivateKey := &sm2.PrivateKey{
|
||||
D: new(big.Int).SetBytes(sk),
|
||||
}
|
||||
sm2PrivateKey.PublicKey.Curve = sm2.Curve()
|
||||
sm2PrivateKey.PublicKey.X = new(big.Int).SetBytes(pk[:sm2.ByteSize()])
|
||||
sm2PrivateKey.PublicKey.Y = new(big.Int).SetBytes(pk[sm2.ByteSize():])
|
||||
|
||||
if _, ok := sdf.Sm2Key[uint32(index)]; !ok {
|
||||
sdf.Sm2Key[uint32(index)] = &Sm2Key{}
|
||||
}
|
||||
sdf.Sm2Key[uint32(index)].encKey = sm2PrivateKey
|
||||
}
|
||||
case KeyTypeSm1:
|
||||
fallthrough
|
||||
case KeyTypeSm4:
|
||||
fallthrough
|
||||
case KeyTypeSm9MasterSign:
|
||||
fallthrough
|
||||
case KeyTypeSm9MasterEnc:
|
||||
fallthrough
|
||||
case KeyTypeSm9UserSign:
|
||||
fallthrough
|
||||
case KeyTypeSm9UserEnc:
|
||||
fallthrough
|
||||
case KeyTypeRsa:
|
||||
fallthrough
|
||||
default:
|
||||
return fmt.Errorf("key type errror")
|
||||
}
|
||||
}
|
||||
|
||||
// now copy sdf to s
|
||||
s.Sm2Key = sdf.Sm2Key
|
||||
s.SymKey = sdf.SymKey
|
||||
s.RsaKey = sdf.RsaKey
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package sdf
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"xdx.jelly/xgcl/api/common"
|
||||
)
|
||||
|
||||
func TestKeyType(t *testing.T) {
|
||||
keyTypes := []KeyType{KeyTypeUnknow,
|
||||
KeyTypeBlock,
|
||||
KeyTypeSm1,
|
||||
KeyTypeSm4,
|
||||
KeyTypeSm2Sign,
|
||||
KeyTypeSm2Enc,
|
||||
KeyTypeSm9MasterSign,
|
||||
KeyTypeSm9MasterEnc,
|
||||
KeyTypeSm9UserSign,
|
||||
KeyTypeSm9UserEnc,
|
||||
KeyTypeRsa,
|
||||
}
|
||||
for _, kt := range keyTypes {
|
||||
if GetKeyType(kt.String()) != kt {
|
||||
t.Fatal("error:", kt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshot(t *testing.T) {
|
||||
|
||||
SDF := &SdfNoLock{}
|
||||
for idx := uint32(0); idx < 10; idx++ {
|
||||
refKey := &common.ECCrefPrivateKey{Bits: 256}
|
||||
SDF.SDF_GenerateRandom(refKey.K[32:])
|
||||
|
||||
var err error
|
||||
err = SDF.ImportSm2KeyAtIndex(idx, KeyTypeSm2Sign, refKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = SDF.ImportSm2KeyAtIndex(idx, KeyTypeSm2Enc, refKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
for idx := uint32(0); idx < 10; idx++ {
|
||||
SDF.GenerateKekAtIndex(idx)
|
||||
}
|
||||
password := []byte("12345")
|
||||
snapshot, err := SDF.Snapshot(true, password, 1000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
snapshotBytes, err := json.MarshalIndent(snapshot, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(string(snapshotBytes))
|
||||
|
||||
var restor Snapshot
|
||||
json.Unmarshal(snapshotBytes, &restor)
|
||||
err = SDF.Restore(&restor, password)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
snapshot2, err := SDF.Snapshot(false, []byte("12345"), 1000)
|
||||
snapshotBytes2, err := json.MarshalIndent(snapshot2, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Println(string(snapshotBytes2))
|
||||
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
package sdf
|
||||
|
||||
import (
|
||||
"xdx.jelly/xgcl/rsa"
|
||||
"xdx.jelly/xgcl/sm/sm2"
|
||||
)
|
||||
|
||||
// assert DefaultSDF is a SDFable interface
|
||||
var _ Sdfable = UnimplementedSDF{}
|
||||
|
||||
type UnimplementedSDF struct{}
|
||||
|
||||
func (UnimplementedSDF) SDF_OpenSession() error {
|
||||
panic("implement me")
|
||||
}
|
||||
func (UnimplementedSDF) SDF_CloseSession() error {
|
||||
panic("implement me")
|
||||
}
|
||||
func (UnimplementedSDF) SDF_GetDeviceInfo() (*DeviceInfo, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
func (UnimplementedSDF) SDF_GetPrivateKeyAccessRight(keyIndex uint32, password []byte) error {
|
||||
panic("implement me")
|
||||
}
|
||||
func (UnimplementedSDF) SDF_ReleasePrivateKeyAccessRight(keyIndex uint32) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateRandom(buffer []byte) (n uint32, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ExportSignPublicKey_RSA(uiKeyIndex uint32) (*rsa.PublicKey, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ExportEncPublicKey_RSA(uiKeyIndex uint32) (*rsa.PublicKey, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeyPair_RSA(uiKeyBits uint32) (*rsa.PublicKey, *rsa.PrivateKey, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeyWithIPK_RSA(uiIPKIndex uint32, uiKeyBits uint32) (pucKey []byte, phKeyHandle interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeyWithEPK_RSA(uiKeyBits uint32, pucPublicKey *rsa.PublicKey) (Key []byte, phKeyHandle interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ImportKeyWithISK_RSA(uiISKIndex uint32, pucKey []byte) (phKeyHandle interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ExchangeDigitEnvelopeBaseOnRSA(uiKeyIndex uint32, pucPublicKey *rsa.PublicKey, pucDEInput []byte) (pucDEOutput []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ExportSignPublicKey_ECC(uiKeyIndex uint32) (*sm2.PublicKey, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ExportEncPublicKey_ECC(uiKeyIndex uint32) (*sm2.PublicKey, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeyPair_ECC(uiAlgID uint32, uiKeyBits uint32) (*sm2.PublicKey, *sm2.PrivateKey, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeyWithIPK_ECC(uiIPKIndex uint32, uiKeyBits uint32) (pucKey *sm2.Cipher, phKeyHandle interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeyWithEPK_ECC(uiKeyBits uint32, uiAlgID uint32, pucPublicKey *sm2.PublicKey) (pucKey *sm2.Cipher, phKeyHandle interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ImportKeyWithISK_ECC(uiISKIndex uint32, pucKey *sm2.Cipher) (phKeyHandle interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateAgreementDataWithECC(uiISKIndex uint32, uiKeyBits uint32, pucSponsorID []byte) (pucSponsorPublicKey *sm2.PublicKey, pucSponsorTmpPublicKey *sm2.PublicKey, phAgreementHandle interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeyWithECC(pucResponseID []byte, pucResponsePublicKey *sm2.PublicKey, pucResponseTmpPublicKey *sm2.PublicKey, hAgreementHandle interface{}) (phKeyHandle interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateAgreementDataAndKeyWithECC(uiISKIndex uint32, uiKeyBits uint32, pucResponseID []byte, pucSponsorID []byte, pucSponsorPublicKey, pucSponsorTmpPublicKey *sm2.PublicKey) (pucResponsePublicKey *sm2.PublicKey, pucResponseTmpPublicKey *sm2.PublicKey, phKeyHandle interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ExchangeDigitEnvelopeBaseOnECC(uiKeyIndex uint32, uiAlgID uint32, pucPublicKey *sm2.PublicKey, pucEncDataIn *sm2.Cipher) (pucEncDataOut *sm2.Cipher, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeyWithKEK(uiKeyBits uint32, uiAlgID uint32, uiKEKIndex uint32) (pucKey []byte, phKeyHandle interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ImportKeyWithKEK(uiAlgID uint32, uiKEKIndex uint32, pucKey []byte) (phKeyHandle interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeywithIKE(pucSponsorNonce []byte, pucResponseNonce []byte, pucSponsorCookie []byte, pucResponseCookie []byte, uiPrfAlgID uint32, uiKeyBitsD, uiKeyBitsA, uiKeyBitsE uint32) (phKeyHandleD interface{}, phKeyHandleA interface{}, phKeyHandleE interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeywithEPK_IKE(pucSponsorNonce []byte, pucResponseNonce []byte, pucSponsorCookie []byte, pucResponseCookie []byte, uiPrfAlgID, uiEccAlgID uint32, pucPublicKey sm2.PublicKey, uiKeyBitsD, uiKeyBitsA, uiKeyBitsE uint32) (pucKeyD *sm2.Cipher, phKeyHandleD interface{}, pucKeyA *sm2.Cipher, phKeyHandleA interface{}, pucKeyE *sm2.Cipher, phKeyHandleE interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeywithIPSEC(pucProtocolID []byte, pucSpi []byte, pucSponsorNonce []byte, pucResponseNonce []byte, hKeyHandle interface{}, uiPrfAlgID uint32, uiKeyBitsEnc, uiKeyBitsMac uint32) (phKeyHandleEnc interface{}, phKeyHandleMac interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeywithEPK_IPSEC(pucProtocolID []byte, pucSpi []byte, pucSponsorNonce []byte, pucResponseNonce []byte, hKeyHandle interface{}, uiPrfAlgID uint32, uiEccAlgID uint32, pucPublicKey *sm2.PublicKey, uiKeyBitsEnc, uiKeyBitsMac uint32) (pucKeyEnc *sm2.Cipher, phKeyHandleEnc interface{}, pucKeyMac *sm2.Cipher, phKeyHandleMac interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeywithSSL(pucKeyPremaster, pucClientRandom, pucServerRandom []byte, uiPrfAlgID uint32, uiKeyBitsClientMac, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc uint32) (phKeyHandleClientMac, phKeyHandleServerMac, phKeyHandleClientEnc, phKeyHandleServerEnc interface{}, pucClientIV, pucServerIV []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeywithEPK_SSL(pucKeyPremaster, pucClientRandom, pucServerRandom []byte, uiPrfAlgID uint32, uiEccAlgID uint32, pucPublicKey *sm2.PublicKey, uiKeyBitsClientMac, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc uint32) (pucKeyClientMac *sm2.Cipher, phKeyHandleClientMac interface{}, pucKeyServerMac *sm2.Cipher, phKeyHandleServerMac interface{}, pucKeyClientEnc *sm2.Cipher, phKeyHandleClientEnc interface{}, pucKeyServerEnc *sm2.Cipher, phKeyHandleServerEnc interface{}, pucClientIV, pucServerIV []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeywithECDHE_SSL(phKeyHandlePremaster interface{}, pucClientRandom, pucServerRandom []byte, uiPrfAlgID uint32, uiKeyBitsClientMac, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc uint32) (phKeyHandleClientMac, phKeyHandleServerMac, phKeyHandleClientEnc, phKeyHandleServerEnc interface{}, pucClientIV, pucServerIV []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_GenerateKeywithEPK_ECDHE_SSL(phKeyHandlePremaster interface{}, pucClientRandom, pucServerRandom []byte, uiPrfAlgID uint32, uiEccAlgID uint32, pucPublicKey *sm2.PublicKey, uiKeyBitsClientMac, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc uint32) (pucKeyClientMac *sm2.Cipher, phKeyHandleClientMac interface{}, pucKeyServerMac *sm2.Cipher, phKeyHandleServerMac interface{}, pucKeyClientEnc *sm2.Cipher, phKeyHandleClientEnc interface{}, pucKeyServerEnc *sm2.Cipher, phKeyHandleServerEnc interface{}, pucClientIV, pucServerIV []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_DestroyKey(hKeyHandle interface{}) error {
|
||||
panic("implement me")
|
||||
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ExternalPublicKeyOperation_RSA(pucPublicKey *rsa.PublicKey, pucDataInput []byte) (pucDataOutput []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_InternalPublicKeyOperation_RSA(uiKeyIndex uint32, pucDataInput []byte) (pucDataOutput []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_InternalPrivateKeyOperation_RSA(uiKeyIndex uint32, pucDataInput []byte) (pucDataOutput []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
func (UnimplementedSDF) SDF_DecryptPublicKeyOperation_RSA(uiKeyIndex uint32, pucDataInput []byte) (pucDataOutput []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ExternalVerify_ECC(uiAlgID uint32, pucPublicKey *sm2.PublicKey, pucDataInput []byte, pucSignature *sm2.Signature) (err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ExternalSign_ECC(uiAlgID uint32, pucPrivateKey *sm2.PrivateKey, pucData []byte) (*sm2.Signature, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_InternalSign_ECC(uiISKIndex uint32, pucData []byte) (pucSignature *sm2.Signature, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_InternalVerify_ECC(uiISKIndex uint32, pucData []byte, pucSignature *sm2.Signature) (err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ExternalEncrypt_ECC(uiAlgID uint32, pucPublicKey *sm2.PublicKey, pucData []byte) (pucEncData *sm2.Cipher, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
func (UnimplementedSDF) SDF_ExternalDecrypt_ECC(uiAlgID uint32, pucPrivateKey *sm2.PrivateKey, pucEncData *sm2.Cipher) (pucData []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
func (UnimplementedSDF) SDF_Encrypt(hKeyHandle interface{}, uiAlgID uint32, pucIV []byte, pucData []byte, pucEncData *[]byte) (err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_Decrypt(hKeyHandle interface{}, uiAlgID uint32, pucIV []byte, pucData []byte, pucEncData *[]byte) (err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_CalculateMAC(hKeyHandle interface{}, uiAlgID uint32, pucIV []byte, pucData []byte) (pucMAC []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_HashInit(uiAlgID uint32, pucPublicKey *sm2.PublicKey, pucID []byte) (err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_HashUpdate(pucData []byte) (err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_HashFinal() (pucHash []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_CreateFile(pucFileName string, uiFileSize uint32) error {
|
||||
panic("implement me")
|
||||
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_ReadFile(pucFileName string, uiOffset uint32, pucBuffer []byte) (n uint32, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_WriteFile(pucFileName string, uiOffset uint32, pucBuffer []byte) error {
|
||||
panic("implement me")
|
||||
|
||||
}
|
||||
|
||||
func (UnimplementedSDF) SDF_DeleteFile(pucFileName string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// 内部sm2私钥解密
|
||||
func (UnimplementedSDF) SDFEXT_InternalDecryptECC(uiKeyIndex uint32, pucEncData *sm2.Cipher) (pucData []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// 6.3.14 生成密钥协商参数并输出-这个与标准接口一致
|
||||
// 描述: 使用ECC密钥协商算法, 为计算会话密钥而产生协商参数, 同时返回指定索引位置的ECC公钥、临时ECC密钥对的公钥及协商句柄。
|
||||
func (UnimplementedSDF) SDFEXT_GenerateAgreementDataWithECC(uiISKIndex uint32, uiKeyBits uint32, pucSponsorID []byte) (pucSponsorPublicKey *sm2.PublicKey, pucSponsorTmpPublicKey *sm2.PublicKey, phAgreementHandle interface{}, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// 6.3.15 计算会话密钥变体
|
||||
// 描述: 使用ECC密钥协商算法, 使用自身协商句柄和响应方的协商参数计算会话密钥, 同时返回会话密钥。
|
||||
// 备注: 协商的发起方获得响应方的协商参数后调用本函数, 计算会话密钥。使用SM2算法计算会话密钥的过程见GM/T 0009。
|
||||
func (UnimplementedSDF) SDFEXT_GenerateKeyWithECC(pucResponseID []byte, pucResponsePublicKey *sm2.PublicKey, pucResponseTmpPublicKey *sm2.PublicKey, hAgreementHandle interface{}) (agreementKey []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// 6.3.16 产生协商数据并计算会话密钥
|
||||
// 描述: 使用ECC密钥协商算法, 产生协商参数并计算会话密钥, 同时返回产生的协商参数和密钥。
|
||||
func (UnimplementedSDF) SDFEXT_GenerateAgreementDataAndKeyWithECC(uiISKIndex uint32, uiKeyBits uint32, pucResponseID []byte, pucSponsorID []byte, pucSponsorPublicKey, pucSponsorTmpPublicKey *sm2.PublicKey) (pucResponsePublicKey *sm2.PublicKey, pucResponseTmpPublicKey *sm2.PublicKey, agreementKey []byte, err error) {
|
||||
panic("implement me")
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
# SM2协同签名的隐私外包计算(Outsourcing Computation)
|
||||
参与方:
|
||||
- 协同签名服务器
|
||||
- 协同签名客户端
|
||||
- **(协同签名客户端)外包服务器**
|
||||
|
||||
其中,协同签名服务端与常规的一致,并且它并不能感知协同签名的客户端是否使用了外包计算。
|
||||
|
||||
外包计算一般应用在协同签名客户端为弱计算环境下,如小程序,浏览器等-当然也可以是APP或PC端。它将协同签名客户端的计算外包给外包服务器。并且外包服务器不能获取所计算的内容的信息。
|
||||
|
||||
## Paillier加密
|
||||
Paillier密钥为:
|
||||
- $p$,$q$为素数,$n=pq$.
|
||||
- $\lambda = \mathrm{LCM}(p-1, q-1)$.
|
||||
|
||||
公钥:$n$.
|
||||
|
||||
私钥:$n, \lambda$
|
||||
|
||||
|
||||
记$\mathrm{Enc},\mathrm{Dec}$为Paillier加密。满足加同态:
|
||||
若
|
||||
$$
|
||||
c_1 = Enc(m_1),\\
|
||||
c_2 = Enc(m_2)
|
||||
$$
|
||||
则
|
||||
$$
|
||||
c_1\cdot c_2 = Enc(m_1 + m_2 \mod n^2)
|
||||
$$
|
||||
|
||||
|
||||
## 签名密钥生成
|
||||
> 原始的协同签名服务端和客户端密钥分别为$d_s,d_c$,并且和实际密钥$d$满足
|
||||
> $$d_s*d_c*(1+d) = 1 \mod N$$
|
||||
|
||||
- 客户端
|
||||
选取
|
||||
$$
|
||||
d_{c1} \leftarrow [1, N-1],
|
||||
$$
|
||||
计算$A_1= \mathrm{Enc}(d_{c1}),A_2 =\mathrm{Enc}(d_{c1}^{-1})$,并发送$A_1,A_2$给外包服务器;
|
||||
- 外包服务器
|
||||
选取
|
||||
$$
|
||||
d_{c2} \leftarrow [1, N-1],
|
||||
$$
|
||||
计算
|
||||
$$
|
||||
\begin{array}{rcl}
|
||||
P &=& [d_{c2}^{-1}]G \\
|
||||
B_1 &=& \mathrm{Enc}(d_{c1})^{d_{c2}}= \mathrm{Enc}(d_{c1}d_{c2}) = \mathrm{Enc}(d_{c})\\
|
||||
B_2&=&\mathrm{Enc}(d_{c2}^{-1})^{d_{c2}^{-1}} = \mathrm{Enc}(d_{c1}^{-1}d_{c2}^{-1})=\mathrm{Enc}(d_{c}^{-1})
|
||||
\end{array}
|
||||
$$
|
||||
|
||||
外包服务器保存$B_1, B_2$, 把$P$,发给客户端
|
||||
- 客户端
|
||||
计算
|
||||
$$
|
||||
Q = [d_{c1}^{-1}]P = [d_{c}^{-1}]G,
|
||||
$$
|
||||
发送$Q$给协同签名服务端。
|
||||
|
||||
- 协同签名服务器计算$R = [d_s^{-1}]G$
|
||||
- 客户端计算公钥$S = [d_{c1}^{-1}]R= [d_{c1}^{-1}d_s^{-1}]G$, 把$(R,S)$发给外包服务器
|
||||
- 外包服务器计算$T_1 = [d_{c2}^{-1}]R, T_2 = [d_{c2}^{-1}]S$, $PK =T_2-G=[d_{c2}^{-1}d_{c1}^{-1}d_s^{-1}-1]G = [d]G$, 把$T_1, PK$
|
||||
- 客户端计算$PK' = [d_{c1}^{-1}]T_1-G$, 并与外包服务器发送的$PK$对比若一致则公钥生成成功。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram;
|
||||
客户端 ->> 外包服务器: A1,A2;
|
||||
外包服务器 ->> 外包服务器: 计算B1,B2并保存;
|
||||
外包服务器 ->> 客户端: P;
|
||||
客户端 ->> 协同签名服务器: Q;
|
||||
协同签名服务器->>客户端: R;
|
||||
客户端 ->> 外包服务器: R,S;
|
||||
外包服务器 ->> 客户端: T1, PK
|
||||
客户端 ->> 客户端: PK;
|
||||
```
|
||||
|
||||
> 1.上述流程中,客户端部分密钥$d_c$未出现,并且客户端参与生成。
|
||||
> 2.客户端与外包服务间应使用HTTPS/TLCP连接防止中间人攻击。
|
||||
> 3.密钥生成后可以通过计算签名验证密钥生成成功。
|
||||
> 4.一种简单的实现是客户端先按常规生成dc,把加密后的dc注册并放到OS上。
|
||||
|
||||
|
||||
|
||||
## 签名流程
|
||||
**前提条件:**
|
||||
|
||||
- 协同签名服务器: $d_s$
|
||||
- 协同签名客户端: Paillier私钥$\lambda$
|
||||
- 外包服务器: Paillier公钥$n$
|
||||
|
||||
|
||||
**签名流程:**
|
||||
|
||||
- 客户端
|
||||
计算e,向外包服务器发起请求
|
||||
- 外包服务器
|
||||
选择随机数$k_1'$, 计算$P' = [k_1']G$,发送$P'$给客户端
|
||||
- 客户端
|
||||
选择随机数$k_1''$, 计算$P = [k_1'']P'=[k_1'k_1'']G$.
|
||||
将$(e,P)$发送给协同签名服务器.
|
||||
> $k_1''$可以取1
|
||||
- 协同签名服务器
|
||||
选择随机数$k_2,k_3$并计算
|
||||
$$
|
||||
\begin{array}{rcl}
|
||||
Q &=& [k_2]P + [k_3]G\\
|
||||
r &=& e + x_Q\\
|
||||
s_1 &=& d_sk_2\\
|
||||
s_2 &=& (k_3 + r)d_s
|
||||
\end{array}
|
||||
$$
|
||||
将$r,s_1,s_2$发送给客户端
|
||||
- 客户端
|
||||
将$r,k_1''s_1,s_2$发送给外包服务器
|
||||
- 外包服务器
|
||||
计算
|
||||
$$
|
||||
\begin{array}{rcl}
|
||||
s' &=& k_1'k_1''s_1+s_2 \mod N\\
|
||||
u &=& Enc(d_c)^{s'} = Enc(d_cs')
|
||||
\end{array}
|
||||
$$
|
||||
选择随机数$k_4 \in [1,N-1]$,计算
|
||||
$$
|
||||
\begin{array}{rcl}
|
||||
v &=& Enc(k_4N)\\
|
||||
w &=& uv = Enc(d_cs' + k_4N)
|
||||
\end{array}
|
||||
$$
|
||||
将$w$发给客户端
|
||||
- 客户端
|
||||
计算
|
||||
$$
|
||||
s = Dec(w) - r \equiv d_cs' - r\mod N
|
||||
$$
|
||||
输出签名值$(r,s)$.
|
||||
```mermaid
|
||||
sequenceDiagram;
|
||||
客户端 ->> 外包服务器: 请求;
|
||||
外包服务器 ->> 外包服务器: k1',P';
|
||||
外包服务器 ->> 客户端: P';
|
||||
客户端 ->> 客户端: k1'', P=[k1'']P';
|
||||
客户端 ->> 协同签名服务器: (e,P);
|
||||
协同签名服务器->>协同签名服务器: 计算r,s1,s2 ;
|
||||
协同签名服务器 ->> 客户端: (r,s1,s2)
|
||||
客户端 ->> 外包服务器: (r,k1s1,s2);
|
||||
外包服务器 ->> 客户端: w = Enc(·);
|
||||
客户端 ->> 客户端: 解密w;
|
||||
客户端 ->> 客户端: 输出签名(r,s);
|
||||
```
|
||||
|
||||
## 使用签名密钥解密加密密钥保护结构
|
||||
**前提条件:**
|
||||
|
||||
- 协同签名客户端外包服务器持有Enc($d_c^{-1}$).
|
||||
|
||||
|
||||
> SM2密文$(C_1,C_3,C_2)$,解密只需要协同计算$[d]C_1 = [d_s^{-1}]\cdot[d_c^{-1}]C_1 - C1$。
|
||||
|
||||
**解密流程:**
|
||||
|
||||
- 客户端
|
||||
把$C_1$发送给外包服务器;
|
||||
- 外包服务器
|
||||
选取随机数$k_1, k_2 \in [1, N-1]$, 计算
|
||||
$$
|
||||
E = \mathrm{Enc}(d_c^{-1})^{k_1} \cdot \mathrm{Enc}(k_2N) = \mathrm{Enc}(d_c^{-1}k_1+k_2N)
|
||||
$$
|
||||
和
|
||||
$$
|
||||
F = [k_1^{-1}]C_1
|
||||
$$
|
||||
把$E,F$发给客户端。
|
||||
- 客户端
|
||||
计算
|
||||
$$
|
||||
\begin{array}{rcl}
|
||||
e &=& \mathrm{Dec}(E) \mod N \equiv d_c^{-1}k_1\\
|
||||
H &=& [e]F = [d_c^{-1}]C_1
|
||||
\end{array}
|
||||
$$
|
||||
- 客户端
|
||||
发送$H$给协同签名服务器
|
||||
- 协同签名服务器
|
||||
计算
|
||||
$$
|
||||
I = [d_s^{-1}]H = [d_s^{-1}d_c^{-1}]G
|
||||
$$
|
||||
发送$I$给客户端
|
||||
- 客户端
|
||||
计算
|
||||
$$
|
||||
J=[d_s^{-1}]\cdot[d_c^{-1}]C_1 - C_1 = [d]C_1
|
||||
$$
|
||||
- 客户端
|
||||
解密得到加密密钥$d_e$(加密密钥明文)。选取随机数$k\in [1,N-1]$,计算
|
||||
$$
|
||||
K = \mathrm{Enc}(d_e)\\
|
||||
L = K^k = \mathrm{Enc}(d_ek)
|
||||
$$
|
||||
$d_{es} = k^{-1} \mod N$. 并将$d_{es}$作为协同签名服务端密钥分量发给服务端,$L$为加密的协同签名客户端密钥分量发给外包服务器。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram;
|
||||
客户端 ->> 外包服务器: C1;
|
||||
外包服务器 ->> 外包服务器: 计算E,F;
|
||||
外包服务器 ->> 客户端: E,F;
|
||||
客户端 ->> 客户端: e = Dec(E), H;
|
||||
客户端 ->> 协同签名服务器: H;
|
||||
协同签名服务器->>协同签名服务器: 计算I;
|
||||
协同签名服务器 ->> 客户端: I
|
||||
客户端 ->> 客户端:计算并得到加密密钥明文;
|
||||
客户端 ->> 客户端:拆分加密密钥;
|
||||
客户端 ->> 协同签名服务器: 服务端部分加密密钥;
|
||||
客户端 ->> 外包服务器: 加密的客户端部分密钥
|
||||
```
|
||||
## 协同解密
|
||||
略,此部分类似使用签名密钥解密流程
|
||||
|
||||
## 口令派生Paillier密钥
|
||||
口令派生出1024bit的字节数组,并转为整数$p'$. $p$为大于$p'$的(满足安全条件)的最小素数。
|
||||
同样派生出$q$(不同的迭代次数)并根据服务端公钥验证。
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package gcl
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
stdkem "crypto/mlkem"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestKyperKatStd(t *testing.T) {
|
||||
dz := make([]byte, 64)
|
||||
for i := 0; i < 64; i++ {
|
||||
dz[i] = byte(i)
|
||||
}
|
||||
|
||||
dk, err := stdkem.NewDecapsulationKey768(dz)
|
||||
assert.Nil(t, err)
|
||||
// ek := dk.EncapsulationKey()
|
||||
// sharedkey, ct := ek.Encapsulate()
|
||||
|
||||
ct, _ := hex.DecodeString("64c8617fee18cca9de7bdd567eeaee5943491b612733131860dbb247f227c42424190270d38763499523e23079c7a8496f404036f5470f985b2c7e1806d511ae2660ff07009f157aa1aadc2ebcb092abfeb0e6faadc094c4cdc9a45b7e740c911ba847388218de90fc489546f3aeeffd09885e6af962506faf568914d5e1fa5148296e958c14128e2b2b95af5a7df3247bef515a198015682fb4353033f4229017c8a63f9a18546c89ee9e995cda3691540276e9d316ff4584afa612c941a00eadbaff6540b3e8c575ebe9d8f13bab919bc698f9df145bcf2a84aba46348146bbe613b82413d5a609747e9ba0e9a0c9758b0d19046ce3d5016b757a4a4d1449dbe46caa93b778b2f45253d54428e8752fc19d854ca2f2994083ebec9556d4ebb17f4837e6f5e7d97821b53ab62d07f49a4fae0a4288228693e0ff093ca6ea7386ccff99a9f28e1b93239c93b797403208ab5a070e491c9a5e5a1130b5a564c365553828c0b649475b53fad68d1fdc1b546ca301aa88a8ba99c828f7c5fd8e6b85f6653306b017e4f4f6044b90c8bf9ed66ebf59bb1b6bbca42bdb31e88b16fd0449574890b78599b9cf12550851fa418151896e86ced8104cf263dd9a0f1fb6922cbd8901807e61fbffdc368cb40613fefd4de5dc89914534e6f866b6f7f9d72e33a395653e3cfbc80da05a755dd421c11e3833ee6f35a899a51f576fb81be01bdf4c62d7e8f47be8bb1e4666c7592aa8f01c601861bb2498e5092fc3e099ceb987685ebce748b3ca6c31038496757fa7b3f3b33f1c425e41d20364addf845bfd116585a941940cdbb53d698db24414653d09aee080b88cd4c63b20f452275b8e13dc839e7bcd2a3d898fc32e0b6707bc6cd60f489a66b760bbf21be8f26ee2e61f94b1d84cfb95b7c66addf9fd3ab16c2f6084da27d1aa33778e6f3eba62dc85e5cbf088d7068bccf3f9574f2c2776265e75e37cb050caa1305d3882d5b77598783987daae6f62fa31e6be6d66ad3e40b7777b3e34c10ded06fb8962bf3ca28b0388ca04ab07d735615f0b842575a066fbf695bf73a8d9da10fa64055f984043369fd5bd0fee87c04e30b9f98a1d4b680b5f35f6ab6f947f3ae8d23922eff86c136835c8b82ccf22c9c138490527fe09b311fee38b410df24655fdc372185e08c43dd823b66ce4aab359169d22cf8f9bad1c0f088583c6c11615a8cb98241e5680698e98f38f179464a7900a939ef5033d5a710c71ceb7a6718608db2b0897af8dda8bcf1a570abe4e6b2280eb2e9b9b5f96366ee2a0ddbea0deb1668dc4ff721e5517f8052a20a5af6af903032bd55939a322cf21168e6ba553f2760d420713405dd975d8b5384d4d23236e34950d9ca27e5edd27eb6ef2935408858eb45a6c2a32827523447af193d54a004972af496bac633dae2557442031fbb1f991bf0deabc5234af6fcf616ed2421c4536d11c26b7f832fecdf7affab325078037dcdcc25bf7c4f5e838d0cd69b07dd75fb73b099bb20d8757d4f4242b77a4dc85065")
|
||||
key, err := dk.Decapsulate(ct)
|
||||
|
||||
fmt.Printf("%x\n", key)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// package gcltests provides algorithm rightness tests
|
||||
// for SM{2,3,4,9}.
|
||||
package gcltests
|
||||
|
||||
// func init() {
|
||||
// if !SM2SignTest() ||
|
||||
// !SM2VerifyTest() ||
|
||||
// !SM3WithIDTest() ||
|
||||
// !SM3Test() ||
|
||||
// !SM4MacTest() ||
|
||||
// !SM4EncECB() ||
|
||||
// !SM4DecECB() ||
|
||||
// !SM4EncCBC() ||
|
||||
// !SM4DecCBC() ||
|
||||
// !SM2TPCKeyGenTest() ||
|
||||
// !SM2TPCSignTest() ||
|
||||
// !SM2TPCDecTest() {
|
||||
// panic("gcl tests failed")
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,28 @@
|
||||
package gcltests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRightness(t *testing.T) {
|
||||
assert.True(t, SM2SignTest())
|
||||
assert.True(t, SM2VerifyTest())
|
||||
assert.True(t, SM2EncryptionTest())
|
||||
assert.True(t, SM2DecryptionTest())
|
||||
|
||||
assert.True(t, SM3WithIDTest())
|
||||
assert.True(t, SM3Test())
|
||||
|
||||
assert.True(t, SM4MacTest())
|
||||
assert.True(t, SM4EncECB())
|
||||
assert.True(t, SM4DecECB())
|
||||
assert.True(t, SM4EncCBC())
|
||||
assert.True(t, SM4DecCBC())
|
||||
|
||||
assert.True(t, SM2TPCKeyGenTest())
|
||||
assert.True(t, SM2TPCSignTest())
|
||||
assert.True(t, SM2TPCDecTest())
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package gcltests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm2"
|
||||
)
|
||||
|
||||
// 算法正确性测试
|
||||
func hexDecode(s string) []byte {
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// SM2SignTest SM2签名算法正确性测试
|
||||
func SM2SignTest() bool {
|
||||
// 先检测SM2签名验证
|
||||
if !SM2VerifyTest() {
|
||||
return false
|
||||
}
|
||||
sk := &sm2.PrivateKey{}
|
||||
sk.SetBytes(hexDecode("C242939DDAB6FCC07B6676C07D2DC117EC68A09142C25C008630B9756786162D"))
|
||||
|
||||
pk := &sm2.PublicKey{}
|
||||
pk.SetBytes(hexDecode("5CA4E440C508C45FE7D758AB10C45D8237C4F9559F7D466185F295399F0AA37D59AD8A3CD17903287681BF9D21DA2EB316A0CE8FD41C89CE1E2B3F1B8E041ABA"))
|
||||
|
||||
e := hexDecode("3854C463FA3F73783621B1CE4EF83F7C78048AAC79B221FCDD290866CC131174")
|
||||
|
||||
sig, err := sm2.Sign(e, grand.GetRandom(32), sk)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return sm2.Verify(e, pk, sig)
|
||||
}
|
||||
|
||||
// SM2VerifyTest SM2签名算法正确性测试
|
||||
func SM2VerifyTest() bool {
|
||||
sk := &sm2.PrivateKey{}
|
||||
sk.SetBytes(hexDecode("C242939DDAB6FCC07B6676C07D2DC117EC68A09142C25C008630B9756786162D"))
|
||||
|
||||
pk := &sm2.PublicKey{}
|
||||
pk.SetBytes(hexDecode("5CA4E440C508C45FE7D758AB10C45D8237C4F9559F7D466185F295399F0AA37D59AD8A3CD17903287681BF9D21DA2EB316A0CE8FD41C89CE1E2B3F1B8E041ABA"))
|
||||
|
||||
e := hexDecode("3854C463FA3F73783621B1CE4EF83F7C78048AAC79B221FCDD290866CC131174")
|
||||
sig := &sm2.Signature{}
|
||||
sig.SetBytes(hexDecode("6E5DB49DBD0992B97040080A96003C721CDB9CF64C88D74321FC2F630ADF37742F6DFF453DFC8D7A506D3F52301BEE529E62FDDD38948F0D5D2CBCBC55900CFA"))
|
||||
|
||||
return sm2.Verify(e, pk, sig)
|
||||
}
|
||||
|
||||
func SM2DecryptionTest() bool {
|
||||
sk := &sm2.PrivateKey{}
|
||||
sk.SetBytes(hexDecode("E7CB09606A53320B347F61F3F142DCB118F723A9BC27879F2805BE778F24AEE5"))
|
||||
|
||||
pk := &sm2.PublicKey{}
|
||||
pk.SetBytes(hexDecode("C4F7D581BEFEF25C8BBB6DAD52A6AB8234FA7DB7A988592BC592DAF2BE630647E3746788CBDC59042D85260DD48B6A7347D82C5314E8AC261588A33151DFCA17"))
|
||||
|
||||
msg := hexDecode("31323334353637383132333435363738")
|
||||
|
||||
cipher := &sm2.Cipher{}
|
||||
cipher.SetBytes(hexDecode("0E09E2BC01614B47F906C2A5F7F660F09DD2207B70E4AEF1B600A65BF273D0B1932E76AD4CE56EC20ED1D8F373E7E5AB09E2248104C7E7023D688F716730180DEF894C493E8D338D091F0F98F23A87AFE4E8AAA4F4FB4BE135B9A1B2073157B66B68E3ADFD914B61E61BA1FC65E5038D"))
|
||||
|
||||
plain, err := sm2.Decrypt(sk, cipher)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(msg, plain) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func SM2EncryptionTest() bool {
|
||||
// 先进行SM2解密测试
|
||||
if !SM2DecryptionTest() {
|
||||
return false
|
||||
}
|
||||
|
||||
sk := &sm2.PrivateKey{}
|
||||
sk.SetBytes(hexDecode("E7CB09606A53320B347F61F3F142DCB118F723A9BC27879F2805BE778F24AEE5"))
|
||||
|
||||
pk := &sm2.PublicKey{}
|
||||
pk.SetBytes(hexDecode("C4F7D581BEFEF25C8BBB6DAD52A6AB8234FA7DB7A988592BC592DAF2BE630647E3746788CBDC59042D85260DD48B6A7347D82C5314E8AC261588A33151DFCA17"))
|
||||
|
||||
msg := hexDecode("31323334353637383132333435363738")
|
||||
cipher, err := sm2.Encrypt(pk, msg, grand.GetRandom(32))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
plain, err := sm2.Decrypt(sk, cipher)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(msg, plain) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package gcltests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm2"
|
||||
"xdx.jelly/xgcl/tpc/sm2/sm2a"
|
||||
)
|
||||
|
||||
// SM2协同签名密钥生成
|
||||
func SM2TPCKeyGenTest() bool {
|
||||
// 先进行SM2签名验证测试
|
||||
if !SM2VerifyTest() {
|
||||
return false
|
||||
}
|
||||
// 生成签名密钥分量和公钥
|
||||
serverKeyCtx := sm2a.NewServerSignKeyGenContext()
|
||||
clientKeyCtx := sm2a.NewClientSignKeyGenContext(grand.Reader)
|
||||
|
||||
buf, err := serverKeyCtx.ServerGenKey_one(grand.Reader)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
buf, err = clientKeyCtx.ClientKeyGen_one(buf)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
buf, err = serverKeyCtx.ServerGenKey_two(buf, grand.Reader)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
buf, err = clientKeyCtx.ClientKeyGen_two(buf)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
err = serverKeyCtx.ServerGenKey_three(buf)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
dc, _ := clientKeyCtx.GetClientKey() // 客户端私钥分量
|
||||
ds, _ := serverKeyCtx.GetServerKey() // 服务端私钥分量
|
||||
pkc, _ := clientKeyCtx.GetPublicKey() // 客户端公钥
|
||||
pks, _ := serverKeyCtx.GetPublicKey() // 服务端公钥
|
||||
if !pkc.Equals(pks) {
|
||||
return false
|
||||
}
|
||||
pk := pkc
|
||||
|
||||
// 协同计算签名
|
||||
e := hexDecode("6F18CAF30D3E0C2F1C59DE6080BA23AF2F4DD49DE5173C4579B8A7FE03A57096")
|
||||
clientSign := sm2a.NewClientSignContext(pk, grand.Reader)
|
||||
buf, _ = clientSign.Initial(e)
|
||||
buf, _ = sm2a.ServerSign(ds, pk, buf, grand.Reader)
|
||||
sig, _ := clientSign.Final(dc, buf)
|
||||
|
||||
// 签名验证
|
||||
if !sm2.Verify(e, pk, sig) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// SM2协同签名验证
|
||||
func SM2TPCSignTest() bool {
|
||||
// 先进行SM2签名验证测试
|
||||
if !SM2VerifyTest() {
|
||||
return false
|
||||
}
|
||||
dc := &sm2.PrivateKey{}
|
||||
dc.SetBytes(hexDecode("5F16B93817200830863BB55A523E131563C639880DA8D5F663C9CA32E872C621"))
|
||||
|
||||
ds := &sm2.PrivateKey{}
|
||||
ds.SetBytes(hexDecode("5749BD354348F66F9905254E784C97BDE700DB7968219829F2DB5EC80D0AB0DF"))
|
||||
pk := &sm2.PublicKey{}
|
||||
pk.SetBytes(hexDecode("C31ED61795626AA8D8D26BB17359160F3CCB63786D50DF2C350C9DD27539DBDA5C2D7FAE4D9360CC77F9C0F7E66DB80ED35CF9969E68A0496BE1120020A4396A"))
|
||||
|
||||
// 协同计算签名
|
||||
e := hexDecode("6F18CAF30D3E0C2F1C59DE6080BA23AF2F4DD49DE5173C4579B8A7FE03A57096")
|
||||
clientSign := sm2a.NewClientSignContext(pk, grand.Reader)
|
||||
buf, _ := clientSign.Initial(e)
|
||||
buf, _ = sm2a.ServerSign(ds, pk, buf, grand.Reader)
|
||||
sig, _ := clientSign.Final(dc, buf)
|
||||
|
||||
// 签名验证
|
||||
if !sm2.Verify(e, pk, sig) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// SM2协同解密验证
|
||||
func SM2TPCDecTest() bool {
|
||||
if !SM2EncryptionTest() {
|
||||
return false
|
||||
}
|
||||
dc := &sm2.PrivateKey{}
|
||||
dc.SetBytes(hexDecode("A17EE7749FC8882D876A1CCE1BCAB13A4F42E28E7EA30B6E81CD068806FE943C"))
|
||||
|
||||
ds := &sm2.PrivateKey{}
|
||||
ds.SetBytes(hexDecode("566760699576E8B3882489B7FB9ED0DE4B467260665156EC131665D929684309"))
|
||||
pk := &sm2.PublicKey{}
|
||||
pk.SetBytes(hexDecode("2B2E90C71D9B16CC4F33D1775E76F5D7C0F283F2D7123504B718788FA38FDB2BBF7F7D94683C498947F365C91C42D7BDC10159E092C158B97BE7B035868949F8"))
|
||||
|
||||
stdPlain := hexDecode("31323334353637383132333435363738")
|
||||
cipher := &sm2.Cipher{}
|
||||
cipher.SetBytes(hexDecode("A098DB078468335D160DCE7A8876B88D56E16173421E96D455FED5039BB3A2F9E4E940F2BA4644C230E63087974EDA8B9C22B0FB116809395060FA73F970D5B3BB43CEDBABC75E8F4F925DC1B58DC9243B4A92668FBA980E4C73DA579B360479A1EEEAEE29BFBD171821EAECBECE675B"))
|
||||
|
||||
// 协同解密
|
||||
clientDecCtx := sm2a.NewClientDecContext()
|
||||
buf, _ := clientDecCtx.Decrypt_one(cipher)
|
||||
buf, _ = sm2a.ServerDecrypt(buf, ds)
|
||||
plain, _ := clientDecCtx.Decrypt_two(buf, dc)
|
||||
|
||||
if !bytes.Equal(plain, stdPlain) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package gcltests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"xdx.jelly/xgcl/sm/sm2"
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
)
|
||||
|
||||
func SM3Test() bool {
|
||||
data := hexDecode("763AFC537F7876C2D0B59FDB68D762E90CEFD222BB358D0D6931867CE26538649BE3579A4004483EA5D84D005063F76FB1CE7E5F2F933B5ED757A718182F383C4D58291A6A5D8D07C081F66806031539093362D854883A8874F7B919925DABC74C173E2162F07E6780E311FF0AEF059AE620303DECB6289E97F72C018723C471")
|
||||
stdDigest := hexDecode("d32b9d793b4966e18c351892e65277756ef0cc9d28db954c959fbb85e3948442")
|
||||
digest := sm3.Sum(data)
|
||||
return bytes.Equal(digest[:], stdDigest)
|
||||
}
|
||||
|
||||
func SM3WithIDTest() bool {
|
||||
pk := &sm2.PublicKey{}
|
||||
pk.SetBytes(hexDecode("127E9EA1805767FD68BF73097231642B3044EEEBB0EBC9A3848100EF455BF5F945709988D547B9E7CB24F276709607A16E25E3B242E54C5FB54DB1F93EE3873E"))
|
||||
id := hexDecode("D208DC5A50CC8144FA7F644D5708655F")
|
||||
|
||||
data := hexDecode("1670390FB93CC01CC2C880BB43454119")
|
||||
stdDigest := hexDecode("FD8FD32ABB888167FD4502DA3F23AC39CA90C87907547D4E334A1CB96E98717B")
|
||||
digest := sm2.PreComputeWithIdAndPubkeyAndMessage(id, data, pk)
|
||||
return bytes.Equal(digest[:], stdDigest)
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package gcltests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"xdx.jelly/xgcl/sm/sm4"
|
||||
)
|
||||
|
||||
func SM4MacTest() bool {
|
||||
key := hexDecode("EEE8A0136E9DBC99F09E29EB5C79DAC1")
|
||||
data := hexDecode("27B16EAF7D0341A1449A14A3D1BD69F9")
|
||||
iv := hexDecode("6071A1EB4C784230A037909D33290854")
|
||||
stdMac := hexDecode("F5CAF5A089C06942F83D1B9BB212F8AF")
|
||||
|
||||
mac, err := sm4.Mac(key, iv, data)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(mac, stdMac)
|
||||
}
|
||||
|
||||
func SM4EncECB() bool {
|
||||
key := hexDecode("C35242CC90CB75935A536F32149F5C35")
|
||||
data := hexDecode("ECB57EE6D15BD06632CFE9FD09B822AF")
|
||||
stdCipher := hexDecode("03D8C466A7C245971925E35540E9209F")
|
||||
cipher, err := sm4.EncryptECB(nil, key, data)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(cipher, stdCipher)
|
||||
}
|
||||
|
||||
func SM4DecECB() bool {
|
||||
key := hexDecode("C35242CC90CB75935A536F32149F5C35")
|
||||
stdData := hexDecode("ECB57EE6D15BD06632CFE9FD09B822AF")
|
||||
cipher := hexDecode("03D8C466A7C245971925E35540E9209F")
|
||||
|
||||
data, err := sm4.DecryptECB(nil, key, cipher)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(data, stdData)
|
||||
}
|
||||
|
||||
func SM4EncCBC() bool {
|
||||
key := hexDecode("99CF573EFE8BE7F3277E800FF793F217")
|
||||
iv := hexDecode("57C1AD66EFD690F45785A0176C42211B")
|
||||
|
||||
data := hexDecode("5B3ADAFFDC04A435D8582B5E04D22CB2920B85FBE0655E2C62DBF15EE6D9D2546D05CA85C78BF757AF9B10C3699879160E52A6060A9F910AA05CFA3F4A58B64D")
|
||||
stdCipher := hexDecode("6A4320D8EC4A544116F5AD9C50EB33AC61A472F451AF2496E7C1761734907AC3A7D474CE21CFA8E64D5CB2D92659FCB4A7F8F5D5DAAFAEA0E3C6078176EB6DD3")
|
||||
cipher, err := sm4.EncryptCBC(nil, iv, key, data)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(cipher, stdCipher)
|
||||
}
|
||||
|
||||
func SM4DecCBC() bool {
|
||||
key := hexDecode("99CF573EFE8BE7F3277E800FF793F217")
|
||||
iv := hexDecode("57C1AD66EFD690F45785A0176C42211B")
|
||||
|
||||
stdData := hexDecode("5B3ADAFFDC04A435D8582B5E04D22CB2920B85FBE0655E2C62DBF15EE6D9D2546D05CA85C78BF757AF9B10C3699879160E52A6060A9F910AA05CFA3F4A58B64D")
|
||||
cipher := hexDecode("6A4320D8EC4A544116F5AD9C50EB33AC61A472F451AF2496E7C1761734907AC3A7D474CE21CFA8E64D5CB2D92659FCB4A7F8F5D5DAAFAEA0E3C6078176EB6DD3")
|
||||
|
||||
data, err := sm4.DecryptCBC(nil, iv, key, cipher)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(data, stdData)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package gerrors
|
||||
|
||||
// 模块错误码定义
|
||||
const (
|
||||
XDX_JELLY_GCL = 0x01000000
|
||||
XDX_JELLY_GCL_SM_SM1 = 0x01001000
|
||||
XDX_JELLY_GCL_SM_SM2 = 0x01002000
|
||||
XDX_JELLY_GCL_SM_SM3 = 0x01003000
|
||||
XDX_JELLY_GCL_SM_SM4 = 0x01004000
|
||||
XDX_JELLY_GCL_SM_SM9 = 0x01009000
|
||||
XDX_JELLY_GCL_SM = 0x0100a000
|
||||
XDX_JELLY_GCL_UTILS_BLOCKMODE = 0x0100b000
|
||||
XDX_JELLY_GCL_SHARING_SSSS = 0x0100c000
|
||||
XDX_JELLY_GCL_GMATH = 0x0100d000
|
||||
XDX_JELLY_GCL_PBKB = 0x0100e000
|
||||
XDX_JELLY_GCL_TPC_SM2_SM2m = 0x0100f000
|
||||
XDX_JELLY_GCL_TPC_SM2_SM2a = 0x01010000
|
||||
XDX_JELLY_GCL_TPC_SM9_SM9m = 0x01011000
|
||||
XDX_JELLY_GCL_GRAND = 0x01012000
|
||||
XDX_JELLY_GCL_GMPKI_SXF = 0x02000000
|
||||
XDX_JELLY_GCL_GMPKI_X509V3 = 0x02001000
|
||||
XDX_JELLY_GCL_GMPKI_IBC = 0x02002000
|
||||
XDX_JELLY_GCL_GMPKI_GSSL = 0x02003000
|
||||
XDX_JELLY_GCL_GMPKI_CERTLESS_GMCERTLESS = 0x02004000
|
||||
)
|
||||
@@ -0,0 +1,46 @@
|
||||
package gerrors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var err0 = errors.New("err0")
|
||||
var err1 = errors.New("err1")
|
||||
|
||||
func fn0() error {
|
||||
return WithStack(WithAnnotating(err0, "comment0"))
|
||||
}
|
||||
|
||||
func fn1() error {
|
||||
if err := fn0(); err != nil {
|
||||
e := ChainErrors(err1, err)
|
||||
return WithStack(WithAnnotating(e, "comment1"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fn2() error {
|
||||
if err := fn1(); err != nil {
|
||||
return WithMessage(err, "err2")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestError(t *testing.T) {
|
||||
|
||||
e := WithAnnotating(err0, "comment0")
|
||||
fmt.Printf("%+v\n", e)
|
||||
fmt.Println()
|
||||
|
||||
if !Is(fn2(), err0) || !Is(fn2(), err1) {
|
||||
t.Fail()
|
||||
}
|
||||
fmt.Println(fn2())
|
||||
fmt.Println()
|
||||
// output:
|
||||
// err2, caused by err1(comment1), caused by err0(comment0)
|
||||
|
||||
fmt.Printf("%+v\n", fn2())
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package gerrors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors/internal/errors" //github.com/pkg/errors
|
||||
)
|
||||
|
||||
// exports github.com/pkg/errors's API
|
||||
var As = errors.As
|
||||
var Is = errors.Is
|
||||
var Cause = errors.Cause
|
||||
var Unwrap = errors.Unwrap
|
||||
var WithMessage = errors.WithMessage
|
||||
var WithMessagef = errors.WithMessagef
|
||||
var WithStack = errors.WithStack
|
||||
var Wrap = errors.Wrap
|
||||
var Wrapf = errors.Wrapf
|
||||
|
||||
// Unused
|
||||
// var Errorf = errors.Errorf
|
||||
// var New = errors.New
|
||||
// type Frame = errors.Frame
|
||||
// type StackTrace = errors.StackTrace
|
||||
|
||||
func Format(code uint32, msg string) string {
|
||||
return fmt.Sprintf("[0x%08x]%s", code, msg)
|
||||
}
|
||||
|
||||
type chainedError struct {
|
||||
err error
|
||||
cause error
|
||||
}
|
||||
|
||||
func (e *chainedError) Error() string {
|
||||
return fmt.Sprintf("%s, caused by %s", e.err, e.cause)
|
||||
}
|
||||
func (e *chainedError) Cause() error {
|
||||
return e.cause
|
||||
}
|
||||
|
||||
func (e *chainedError) Unwrap() error {
|
||||
return e.cause
|
||||
}
|
||||
|
||||
// 定义fmt.Printf("%+v", e)打印格式
|
||||
func (e *chainedError) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
if e := e.Cause(); e != nil {
|
||||
fmt.Fprintf(s, "%+v\n", e)
|
||||
}
|
||||
_, _ = io.WriteString(s, e.err.Error())
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
_, _ = io.WriteString(s, e.Error())
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (e *chainedError) Is(target error) bool {
|
||||
return Is(e.err, target) || Is(e.cause, target)
|
||||
}
|
||||
|
||||
func ChainErrors(e error, cause error) error {
|
||||
return &chainedError{
|
||||
err: e,
|
||||
cause: cause,
|
||||
}
|
||||
}
|
||||
|
||||
// withAnnotating wraps an error with annotatings.
|
||||
type withAnnotating struct {
|
||||
err error
|
||||
annotating string
|
||||
}
|
||||
|
||||
func (e *withAnnotating) Error() string {
|
||||
return fmt.Sprintf("%s(%s)", e.err, e.annotating)
|
||||
}
|
||||
|
||||
func (e *withAnnotating) Cause() error {
|
||||
return Cause(e.err)
|
||||
}
|
||||
|
||||
func (e *withAnnotating) Unwrap() error {
|
||||
return Unwrap(e.err)
|
||||
}
|
||||
|
||||
func (e *withAnnotating) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
if e := e.Cause(); e != nil {
|
||||
fmt.Fprintf(s, "%+v\n", e)
|
||||
}
|
||||
io.WriteString(s, e.Error())
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
_, _ = io.WriteString(s, e.Error())
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (e *withAnnotating) Is(target error) bool {
|
||||
return Is(e.err, target)
|
||||
}
|
||||
|
||||
// WithAnnotating add an annotating to err
|
||||
func WithAnnotating(err error, annotating string) error {
|
||||
switch err := err.(type) {
|
||||
case *chainedError:
|
||||
err.err = WithAnnotating(err.err, annotating)
|
||||
return err
|
||||
default:
|
||||
return &withAnnotating{
|
||||
err: err,
|
||||
annotating: annotating,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithAnnotatingf add an format annotating to err
|
||||
func WithAnnotatingf(err error, format string, args ...interface{}) error {
|
||||
return WithAnnotating(err, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
type ErrorCode uint32
|
||||
|
||||
func (e ErrorCode) Error() string {
|
||||
return Format(uint32(e), "")
|
||||
}
|
||||
|
||||
func (e ErrorCode) Code() uint32 {
|
||||
return uint32(e)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# 错误码基线
|
||||
"xdx.jelly/xgcl": 0x01000000,
|
||||
"xdx.jelly/xgcl/sm/sm1": 0x01001000,
|
||||
"xdx.jelly/xgcl/sm/sm2": 0x01002000,
|
||||
"xdx.jelly/xgcl/sm/sm3": 0x01003000,
|
||||
"xdx.jelly/xgcl/sm/sm4": 0x01004000,
|
||||
"xdx.jelly/xgcl/sm/sm9": 0x01009000,
|
||||
"xdx.jelly/xgcl/sm": 0x0100a000,
|
||||
"xdx.jelly/xgcl/utils/blockmode": 0x0100b000,
|
||||
"xdx.jelly/xgcl/sharing/ssss": 0x0100c000,
|
||||
"xdx.jelly/xgcl/gmath": 0x0100d000,
|
||||
"xdx.jelly/xgcl/pbkd": 0x0100e000,
|
||||
"xdx.jelly/xgcl/tpc/sm2/sm2m": 0x0100f000,
|
||||
"xdx.jelly/xgcl/tpc/sm2/sm2a": 0x01010000,
|
||||
"xdx.jelly/xgcl/tpc/sm9/sm9m": 0x01011000,
|
||||
"xdx.jelly/xgcl/grand": 0x01012000,
|
||||
|
||||
"xdx.jelly/xgcl/gmpki/sxf": 0x02000000,
|
||||
"xdx.jelly/xgcl/gmpki/x509v3": 0x02001000,
|
||||
"xdx.jelly/xgcl/gmpki/ibc": 0x02002000,
|
||||
"xdx.jelly/xgcl/gmpki/gssl": 0x02003000,
|
||||
"xdx.jelly/xgcl/gmpki/certless/gmcertless": 0x02004000,
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,59 @@
|
||||
# errors [](https://travis-ci.org/pkg/errors) [](https://ci.appveyor.com/project/davecheney/errors/branch/master) [](http://godoc.org/github.com/pkg/errors) [](https://goreportcard.com/report/github.com/pkg/errors) [](https://sourcegraph.com/github.com/pkg/errors?badge)
|
||||
|
||||
Package errors provides simple error handling primitives.
|
||||
|
||||
`go get github.com/pkg/errors`
|
||||
|
||||
The traditional error handling idiom in Go is roughly akin to
|
||||
```go
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
|
||||
|
||||
## Adding context to an error
|
||||
|
||||
The errors.Wrap function returns a new error that adds context to the original error. For example
|
||||
```go
|
||||
_, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "read failed")
|
||||
}
|
||||
```
|
||||
## Retrieving the cause of an error
|
||||
|
||||
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
|
||||
```go
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
```
|
||||
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
|
||||
```go
|
||||
switch err := errors.Cause(err).(type) {
|
||||
case *MyError:
|
||||
// handle specifically
|
||||
default:
|
||||
// unknown error
|
||||
}
|
||||
```
|
||||
|
||||
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
|
||||
|
||||
## Roadmap
|
||||
|
||||
With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows:
|
||||
|
||||
- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible)
|
||||
- 1.0. Final release.
|
||||
|
||||
## Contributing
|
||||
|
||||
Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports.
|
||||
|
||||
Before sending a PR, please discuss your change by raising an issue.
|
||||
|
||||
## License
|
||||
|
||||
BSD-2-Clause
|
||||
@@ -0,0 +1,295 @@
|
||||
// Package errors provides simple error handling primitives.
|
||||
//
|
||||
// The traditional error handling idiom in Go is roughly akin to
|
||||
//
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// which when applied recursively up the call stack results in error reports
|
||||
// without context or debugging information. The errors package allows
|
||||
// programmers to add context to the failure path in their code in a way
|
||||
// that does not destroy the original value of the error.
|
||||
//
|
||||
// # Adding context to an error
|
||||
//
|
||||
// The errors.Wrap function returns a new error that adds context to the
|
||||
// original error by recording a stack trace at the point Wrap is called,
|
||||
// together with the supplied message. For example
|
||||
//
|
||||
// _, err := ioutil.ReadAll(r)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "read failed")
|
||||
// }
|
||||
//
|
||||
// If additional control is required, the errors.WithStack and
|
||||
// errors.WithMessage functions destructure errors.Wrap into its component
|
||||
// operations: annotating an error with a stack trace and with a message,
|
||||
// respectively.
|
||||
//
|
||||
// # Retrieving the cause of an error
|
||||
//
|
||||
// Using errors.Wrap constructs a stack of errors, adding context to the
|
||||
// preceding error. Depending on the nature of the error it may be necessary
|
||||
// to reverse the operation of errors.Wrap to retrieve the original error
|
||||
// for inspection. Any error value which implements this interface
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
||||
// the topmost error that does not implement causer, which is assumed to be
|
||||
// the original cause. For example:
|
||||
//
|
||||
// switch err := errors.Cause(err).(type) {
|
||||
// case *MyError:
|
||||
// // handle specifically
|
||||
// default:
|
||||
// // unknown error
|
||||
// }
|
||||
//
|
||||
// Although the causer interface is not exported by this package, it is
|
||||
// considered a part of its stable public interface.
|
||||
//
|
||||
// # Formatted printing of errors
|
||||
//
|
||||
// All error values returned from this package implement fmt.Formatter and can
|
||||
// be formatted by the fmt package. The following verbs are supported:
|
||||
//
|
||||
// %s print the error. If the error has a Cause it will be
|
||||
// printed recursively.
|
||||
// %v see %s
|
||||
// %+v extended format. Each Frame of the error's StackTrace will
|
||||
// be printed in detail.
|
||||
//
|
||||
// # Retrieving the stack trace of an error or wrapper
|
||||
//
|
||||
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
||||
// invoked. This information can be retrieved with the following interface:
|
||||
//
|
||||
// type stackTracer interface {
|
||||
// StackTrace() errors.StackTrace
|
||||
// }
|
||||
//
|
||||
// The returned errors.StackTrace type is defined as
|
||||
//
|
||||
// type StackTrace []Frame
|
||||
//
|
||||
// The Frame type represents a call site in the stack trace. Frame supports
|
||||
// the fmt.Formatter interface that can be used for printing information about
|
||||
// the stack trace of this error. For example:
|
||||
//
|
||||
// if err, ok := err.(stackTracer); ok {
|
||||
// for _, f := range err.StackTrace() {
|
||||
// fmt.Printf("%+s:%d\n", f, f)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Although the stackTracer interface is not exported by this package, it is
|
||||
// considered a part of its stable public interface.
|
||||
//
|
||||
// See the documentation for Frame.Format for more details.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// New returns an error with the supplied message.
|
||||
// New also records the stack trace at the point it was called.
|
||||
func New(message string) error {
|
||||
return &fundamental{
|
||||
msg: message,
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Errorf formats according to a format specifier and returns the string
|
||||
// as a value that satisfies error.
|
||||
// Errorf also records the stack trace at the point it was called.
|
||||
func Errorf(format string, args ...interface{}) error {
|
||||
return &fundamental{
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// fundamental is an error that has a message and a stack, but no caller.
|
||||
type fundamental struct {
|
||||
msg string
|
||||
*stack
|
||||
}
|
||||
|
||||
func (f *fundamental) Error() string { return f.msg }
|
||||
|
||||
func (f *fundamental) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
io.WriteString(s, f.msg)
|
||||
f.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, f.msg)
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", f.msg)
|
||||
}
|
||||
}
|
||||
|
||||
// WithStack annotates err with a stack trace at the point WithStack was called.
|
||||
// If err is nil, WithStack returns nil.
|
||||
func WithStack(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
type withStack struct {
|
||||
error
|
||||
*stack
|
||||
}
|
||||
|
||||
func (w *withStack) Cause() error { return w.error }
|
||||
|
||||
// Unwrap provides compatibility for Go 1.13 error chains.
|
||||
func (w *withStack) Unwrap() error { return w.error }
|
||||
|
||||
func (w *withStack) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
if e := w.Cause(); e != nil {
|
||||
fmt.Fprintf(s, "%+v", e)
|
||||
}
|
||||
w.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, w.Error())
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap returns an error annotating err with a stack trace
|
||||
// at the point Wrap is called, and the supplied message.
|
||||
// If err is nil, Wrap returns nil.
|
||||
func Wrap(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapf returns an error annotating err with a stack trace
|
||||
// at the point Wrapf is called, and the format specifier.
|
||||
// If err is nil, Wrapf returns nil.
|
||||
func Wrapf(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessage annotates err with a new message.
|
||||
// If err is nil, WithMessage returns nil.
|
||||
func WithMessage(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessagef annotates err with the format specifier.
|
||||
// If err is nil, WithMessagef returns nil.
|
||||
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
}
|
||||
|
||||
type withMessage struct {
|
||||
cause error
|
||||
msg string
|
||||
}
|
||||
|
||||
func (w *withMessage) Error() string { return w.msg + ", caused by " + w.cause.Error() }
|
||||
func (w *withMessage) Cause() error { return w.cause }
|
||||
|
||||
// Unwrap provides compatibility for Go 1.13 error chains.
|
||||
func (w *withMessage) Unwrap() error { return w.cause }
|
||||
|
||||
func (w *withMessage) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
if e := w.Cause(); e != nil {
|
||||
fmt.Fprintf(s, "%+v\n", e)
|
||||
}
|
||||
io.WriteString(s, w.msg)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's', 'q':
|
||||
io.WriteString(s, w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Cause returns the underlying cause of the error, if possible.
|
||||
// An error value has a cause if it implements the following
|
||||
// interface:
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// If the error does not implement Cause, the original error will
|
||||
// be returned. If the error is nil, nil will be returned without further
|
||||
// investigation.
|
||||
//
|
||||
// Note: We modify the returned error to nil if the err does not implement Cause.
|
||||
func Cause(err error) error {
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
|
||||
for err != nil {
|
||||
cause, ok := err.(causer)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
err = cause.Cause()
|
||||
}
|
||||
// return err
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// +build go1.13
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
stderrors "errors"
|
||||
)
|
||||
|
||||
// Is reports whether any error in err's chain matches target.
|
||||
//
|
||||
// The chain consists of err itself followed by the sequence of errors obtained by
|
||||
// repeatedly calling Unwrap.
|
||||
//
|
||||
// An error is considered to match a target if it is equal to that target or if
|
||||
// it implements a method Is(error) bool such that Is(target) returns true.
|
||||
func Is(err, target error) bool { return stderrors.Is(err, target) }
|
||||
|
||||
// As finds the first error in err's chain that matches target, and if so, sets
|
||||
// target to that error value and returns true.
|
||||
//
|
||||
// The chain consists of err itself followed by the sequence of errors obtained by
|
||||
// repeatedly calling Unwrap.
|
||||
//
|
||||
// An error matches target if the error's concrete value is assignable to the value
|
||||
// pointed to by target, or if the error has a method As(interface{}) bool such that
|
||||
// As(target) returns true. In the latter case, the As method is responsible for
|
||||
// setting target.
|
||||
//
|
||||
// As will panic if target is not a non-nil pointer to either a type that implements
|
||||
// error, or to any interface type. As returns false if err is nil.
|
||||
func As(err error, target interface{}) bool { return stderrors.As(err, target) }
|
||||
|
||||
// Unwrap returns the result of calling the Unwrap method on err, if err's
|
||||
// type contains an Unwrap method returning error.
|
||||
// Otherwise, Unwrap returns nil.
|
||||
func Unwrap(err error) error {
|
||||
return stderrors.Unwrap(err)
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Frame represents a program counter inside a stack frame.
|
||||
// For historical reasons if Frame is interpreted as a uintptr
|
||||
// its value represents the program counter + 1.
|
||||
type Frame uintptr
|
||||
|
||||
// pc returns the program counter for this frame;
|
||||
// multiple frames may have the same PC value.
|
||||
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
|
||||
|
||||
// file returns the full path to the file that contains the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) file() string {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return "unknown"
|
||||
}
|
||||
file, _ := fn.FileLine(f.pc())
|
||||
return file
|
||||
}
|
||||
|
||||
// line returns the line number of source code of the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) line() int {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return 0
|
||||
}
|
||||
_, line := fn.FileLine(f.pc())
|
||||
return line
|
||||
}
|
||||
|
||||
// name returns the name of this function, if known.
|
||||
func (f Frame) name() string {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return "unknown"
|
||||
}
|
||||
return fn.Name()
|
||||
}
|
||||
|
||||
// Format formats the frame according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s source file
|
||||
// %d source line
|
||||
// %n function name
|
||||
// %v equivalent to %s:%d
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+s function name and path of source file relative to the compile time
|
||||
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
||||
// %+v equivalent to %+s:%d
|
||||
func (f Frame) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
io.WriteString(s, f.name())
|
||||
io.WriteString(s, "\n\t")
|
||||
io.WriteString(s, f.file())
|
||||
default:
|
||||
io.WriteString(s, path.Base(f.file()))
|
||||
}
|
||||
case 'd':
|
||||
io.WriteString(s, strconv.Itoa(f.line()))
|
||||
case 'n':
|
||||
io.WriteString(s, funcname(f.name()))
|
||||
case 'v':
|
||||
f.Format(s, 's')
|
||||
io.WriteString(s, ":")
|
||||
f.Format(s, 'd')
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalText formats a stacktrace Frame as a text string. The output is the
|
||||
// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
|
||||
func (f Frame) MarshalText() ([]byte, error) {
|
||||
name := f.name()
|
||||
if name == "unknown" {
|
||||
return []byte(name), nil
|
||||
}
|
||||
return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
|
||||
}
|
||||
|
||||
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
||||
type StackTrace []Frame
|
||||
|
||||
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s lists source files for each Frame in the stack
|
||||
// %v lists the source file and line number for each Frame in the stack
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+v Prints filename, function, and line number for each Frame in the stack.
|
||||
func (st StackTrace) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
for _, f := range st {
|
||||
io.WriteString(s, "\n")
|
||||
f.Format(s, verb)
|
||||
}
|
||||
case s.Flag('#'):
|
||||
fmt.Fprintf(s, "%#v", []Frame(st))
|
||||
default:
|
||||
st.formatSlice(s, verb)
|
||||
}
|
||||
case 's':
|
||||
st.formatSlice(s, verb)
|
||||
}
|
||||
}
|
||||
|
||||
// formatSlice will format this StackTrace into the given buffer as a slice of
|
||||
// Frame, only valid when called with '%s' or '%v'.
|
||||
func (st StackTrace) formatSlice(s fmt.State, verb rune) {
|
||||
io.WriteString(s, "[")
|
||||
for i, f := range st {
|
||||
if i > 0 {
|
||||
io.WriteString(s, " ")
|
||||
}
|
||||
f.Format(s, verb)
|
||||
}
|
||||
io.WriteString(s, "]")
|
||||
}
|
||||
|
||||
// stack represents a stack of program counters.
|
||||
type stack []uintptr
|
||||
|
||||
func (s *stack) Format(st fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case st.Flag('+'):
|
||||
for _, pc := range *s {
|
||||
f := Frame(pc)
|
||||
fmt.Fprintf(st, "\n%+v", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stack) StackTrace() StackTrace {
|
||||
f := make([]Frame, len(*s))
|
||||
for i := 0; i < len(f); i++ {
|
||||
f[i] = Frame((*s)[i])
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func callers() *stack {
|
||||
const depth = 32
|
||||
var pcs [depth]uintptr
|
||||
n := runtime.Callers(3, pcs[:])
|
||||
var st stack = pcs[0:n]
|
||||
return &st
|
||||
}
|
||||
|
||||
// funcname removes the path prefix component of a function's name reported by func.Name().
|
||||
func funcname(name string) string {
|
||||
i := strings.LastIndex(name, "/")
|
||||
name = name[i+1:]
|
||||
i = strings.Index(name, ".")
|
||||
return name[i+1:]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
///
|
||||
/// Copyright (c) 2018 xdx. All rights reserved.
|
||||
///
|
||||
/// \file: doc.go
|
||||
///
|
||||
/// \brief:
|
||||
///
|
||||
/// \author: xdx
|
||||
///
|
||||
|
||||
/*
|
||||
Package gmath (mathematical Library) is the basic mathematical library
|
||||
Named as gmath is easy to auto imports.
|
||||
*/
|
||||
package gmath
|
||||
@@ -0,0 +1,17 @@
|
||||
package gmath
|
||||
|
||||
import (
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
)
|
||||
|
||||
//go:generate stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go
|
||||
type ErrorCode gerrors.ErrorCode
|
||||
|
||||
func (e ErrorCode) Error() string {
|
||||
return gerrors.Format(uint32(e), e.String())
|
||||
}
|
||||
|
||||
// error codes
|
||||
const (
|
||||
ErrBufTooShort ErrorCode = 0x0100d000 + iota //缓冲区太小
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
// Code generated by "stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go"; DO NOT EDIT.
|
||||
|
||||
package gmath
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[ErrBufTooShort-16830464]
|
||||
}
|
||||
|
||||
const _ErrorCode_name = "缓冲区太小"
|
||||
|
||||
var _ErrorCode_index = [...]uint8{0, 15}
|
||||
|
||||
func (i ErrorCode) String() string {
|
||||
i -= 16830464
|
||||
if i >= ErrorCode(len(_ErrorCode_index)-1) {
|
||||
return "ErrorCode(" + strconv.FormatInt(int64(i+16830464), 10) + ")"
|
||||
}
|
||||
return _ErrorCode_name[_ErrorCode_index[i]:_ErrorCode_index[i+1]]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
//go:build !go1.15
|
||||
// +build !go1.15
|
||||
|
||||
package gmath
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// FillBytes fill the buf with the abs of a in big-endian with zero extention.
|
||||
// if buf is two short, then return error, while Big.Int's FillBytes panic
|
||||
func FillBytes(a *big.Int, buf []byte) error {
|
||||
if (a.BitLen()+7)/8 > len(buf) {
|
||||
return ErrBufTooShort
|
||||
}
|
||||
|
||||
b := ToNBytes(a, len(buf))
|
||||
copy(buf, b)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//go:build go1.15
|
||||
// +build go1.15
|
||||
|
||||
package gmath
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// FillBytes fill the buf with the abs of a in big-endian with zero extention.
|
||||
// if buf is too short, then return error, while Big.Int's FillBytes panic
|
||||
func FillBytes(a *big.Int, buf []byte) error {
|
||||
if (a.BitLen()+7)/8 > len(buf) {
|
||||
return ErrBufTooShort
|
||||
}
|
||||
a.FillBytes(buf)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package gmath
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// BigIntx is a big.Int of x
|
||||
var (
|
||||
BigInt0 = big.NewInt(0)
|
||||
BigInt1 = big.NewInt(1)
|
||||
BigInt2 = big.NewInt(2)
|
||||
BigInt3 = big.NewInt(3)
|
||||
BigInt4 = big.NewInt(4)
|
||||
BigInt5 = big.NewInt(5)
|
||||
BigInt6 = big.NewInt(6)
|
||||
BigInt7 = big.NewInt(7)
|
||||
BigInt8 = big.NewInt(8)
|
||||
BigInt9 = big.NewInt(9)
|
||||
BigInt10 = big.NewInt(10)
|
||||
BigInt11 = big.NewInt(11)
|
||||
BigInt12 = big.NewInt(12)
|
||||
BigInt2256 = new(big.Int).Lsh(BigInt1, 256) // = 2^256
|
||||
)
|
||||
|
||||
// IsBigInt0 return if x==0
|
||||
func IsBigInt0(x *big.Int) bool {
|
||||
return x.Sign() == 0
|
||||
}
|
||||
|
||||
// IsBigInt1 return if x==0
|
||||
func IsBigInt1(x *big.Int) bool {
|
||||
return x.Cmp(BigInt1) == 0
|
||||
}
|
||||
|
||||
// ClearBigInt set memory of x be 0
|
||||
func ClearBigInt(x *big.Int) {
|
||||
if x == nil {
|
||||
return
|
||||
}
|
||||
words := x.Bits()
|
||||
for i := range words {
|
||||
words[i] = 0
|
||||
}
|
||||
x.SetInt64(0)
|
||||
}
|
||||
|
||||
type bytes interface {
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
// ToNBytes ouput a bytes to fix n bytes. extend as 0.
|
||||
func ToNBytes(b bytes, n int) []byte {
|
||||
abs := b.Bytes()
|
||||
l := len(abs)
|
||||
var s []byte
|
||||
// l==n is the most case (255/256)
|
||||
if l >= n {
|
||||
s = abs[l-n : l]
|
||||
} else {
|
||||
s = make([]byte, n)
|
||||
copy(s[n-l:], abs)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// BigIntToNByte return a n byte slice of the input big.Int as big-endian
|
||||
// if len(a.Bytes()) > n, then only the lower n bytes are return
|
||||
func BigIntToNByte(a *big.Int, n int) []byte {
|
||||
return ToNBytes(a, n)
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package gmath
|
||||
|
||||
import (
|
||||
stdbytes "bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
)
|
||||
|
||||
func TestBig(t *testing.T) {
|
||||
b := grand.Int(0)
|
||||
fmt.Println(b.Bytes(), b.BitLen())
|
||||
a := BigInt2256.Neg(BigInt2256)
|
||||
BigInt2256.Neg(BigInt2256)
|
||||
b, _ = rand.Int(grand.Reader, a)
|
||||
fmt.Println(BigInt2256.Text(16))
|
||||
fmt.Println(b.Text(16))
|
||||
b, _ = rand.Int(grand.Reader, BigInt2)
|
||||
fmt.Println(b)
|
||||
}
|
||||
|
||||
func TestFillBytes(t *testing.T) {
|
||||
a, _ := new(big.Int).SetString("123455", 16)
|
||||
buf := make([]byte, 1)
|
||||
// buf[2] = 1
|
||||
fmt.Printf("%02x\n", buf)
|
||||
err := FillBytes(a, buf)
|
||||
fmt.Printf("%02x %v\n", buf, err)
|
||||
fmt.Println("over")
|
||||
}
|
||||
|
||||
func opensslIsPrime(n *big.Int) bool {
|
||||
cmd := exec.Command("openssl", "prime", "-hex", n.Text(16))
|
||||
buf, err := cmd.Output()
|
||||
if err != nil || stdbytes.Contains(buf, []byte("not prime")) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestIsPrimeMR(t *testing.T) {
|
||||
bits := 1024
|
||||
n := grand.Int(bits)
|
||||
count := 1
|
||||
for !IsPrimeMR(n) {
|
||||
count++
|
||||
n = grand.Int(bits)
|
||||
}
|
||||
fmt.Println("random times: ", count)
|
||||
fmt.Println(n.Text(16))
|
||||
if !opensslIsPrime(n) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestZp(t *testing.T) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("panic:", err)
|
||||
fmt.Println("recover")
|
||||
}
|
||||
}()
|
||||
|
||||
p, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16)
|
||||
a := NewZp(p)
|
||||
b := NewZp(p)
|
||||
c := NewZp(p)
|
||||
a.SetString("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16)
|
||||
b.SetString("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16)
|
||||
|
||||
c.Add(a, b)
|
||||
fmt.Println("a+b= ", c)
|
||||
|
||||
c.Sub(b, a)
|
||||
fmt.Println("b-a= ", c)
|
||||
|
||||
c.Mul(b, a)
|
||||
fmt.Println("a*b= ", c)
|
||||
|
||||
c.Inv(b)
|
||||
fmt.Println("b^(-1)=", c)
|
||||
|
||||
b.SetInt(0)
|
||||
c.Inv(b)
|
||||
fmt.Println("0^(-1)=", c)
|
||||
|
||||
}
|
||||
|
||||
func TestRandom(t *testing.T) {
|
||||
p, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16)
|
||||
a := NewZp(p)
|
||||
if err := a.Random(); err != nil {
|
||||
t.Failed()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package gmath
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
)
|
||||
|
||||
const MRConst = 10
|
||||
|
||||
// IsPrimeMR tests if n is prime by the Miller-Rabin prime testing method.
|
||||
func IsPrimeMR(n *big.Int) bool {
|
||||
return n.ProbablyPrime(MRConst)
|
||||
}
|
||||
|
||||
// MillerRabin tests if n is prime by the Miller-Rabin prime testing method.
|
||||
func MillerRabin(n *big.Int) bool {
|
||||
// n = 2^s * r
|
||||
n1 := new(big.Int)
|
||||
n1.Sub(n, BigInt1)
|
||||
r := new(big.Int).Set(n1)
|
||||
s := 0
|
||||
for r.Bit(0) == 0 {
|
||||
s++
|
||||
r = r.Rsh(r, 1)
|
||||
}
|
||||
|
||||
for i := 0; i < MRConst; i++ {
|
||||
a, _ := rand.Int(grand.Reader, n1)
|
||||
|
||||
//a = a^r mod n
|
||||
a.Exp(a, r, n)
|
||||
if a.Cmp(BigInt1) != 0 && a.Cmp(n1) != 0 {
|
||||
for j := 1; j < s && a.Cmp(n1) != 0; j++ {
|
||||
a.Mul(a, a)
|
||||
a.Mod(a, n)
|
||||
if a.Cmp(BigInt1) == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if a.Cmp(n1) != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
package gmath
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
)
|
||||
|
||||
// Zp is a simple wrap of big.Int, to comput in integers mod p
|
||||
type Zp struct {
|
||||
d *big.Int
|
||||
p *big.Int
|
||||
byteSize int
|
||||
}
|
||||
|
||||
func (z *Zp) init(p *big.Int) *Zp {
|
||||
z.d = new(big.Int)
|
||||
z.p = p
|
||||
z.byteSize = len(z.p.Bytes())
|
||||
return z
|
||||
}
|
||||
|
||||
// a to bytes slice, big endian, padding 0
|
||||
// 0x123456 =>
|
||||
// 00 00 00 00 ... 12 34 56 78 -- total nBytes
|
||||
// note:
|
||||
// if a.Bytes() are longer than nBytes, then
|
||||
// only the nBytes of lower are return. i.e
|
||||
// the return value is a mod 2^{8*nBytes}
|
||||
func intToByte(a *big.Int, nBytes int) []byte {
|
||||
abs := a.Bytes()
|
||||
l := len(abs)
|
||||
s := make([]byte, nBytes)
|
||||
if nBytes > l {
|
||||
copy(s[nBytes-l:], abs)
|
||||
} else {
|
||||
copy(s, abs[l-nBytes:])
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// NewZp ...
|
||||
func NewZp(p *big.Int) *Zp {
|
||||
return new(Zp).init(p)
|
||||
}
|
||||
|
||||
// Clear set memory to 0
|
||||
func (z *Zp) Clear() {
|
||||
abs := z.d.Bytes()
|
||||
for i := range abs {
|
||||
abs[i] = 0
|
||||
}
|
||||
z.SetInt(0)
|
||||
}
|
||||
|
||||
// GetInteger return the d (0 < d < p)
|
||||
func (z *Zp) GetInteger() *big.Int {
|
||||
return z.Normalize().d
|
||||
}
|
||||
|
||||
// GetPrime return the p
|
||||
func (z *Zp) GetPrime() *big.Int {
|
||||
return z.p
|
||||
}
|
||||
|
||||
// Set z to x
|
||||
func (z *Zp) Set(x *Zp) *Zp {
|
||||
z.d.Set(x.d)
|
||||
z.p = x.p
|
||||
return z
|
||||
}
|
||||
|
||||
// SetInt ...
|
||||
func (z *Zp) SetInt(n int) *Zp {
|
||||
z.d.SetInt64(int64(n))
|
||||
return z
|
||||
}
|
||||
|
||||
// SetBigInt ...
|
||||
func (z *Zp) SetBigInt(n *big.Int) *Zp {
|
||||
z.d.Set(n)
|
||||
return z
|
||||
}
|
||||
|
||||
// SetString ...
|
||||
func (z *Zp) SetString(s string, base int) (*Zp, bool) {
|
||||
_, err := z.d.SetString(s, base)
|
||||
return z, err
|
||||
}
|
||||
|
||||
// SetBytes ...
|
||||
func (z *Zp) SetBytes(buf []byte) *Zp {
|
||||
z.d.SetBytes(buf)
|
||||
return z
|
||||
}
|
||||
|
||||
// Is0 ...
|
||||
func (z *Zp) Is0() bool {
|
||||
z.Normalize()
|
||||
return IsBigInt0(z.d)
|
||||
}
|
||||
|
||||
// Is1 ...
|
||||
func (z *Zp) Is1() bool {
|
||||
z.Normalize()
|
||||
return IsBigInt1(z.d)
|
||||
}
|
||||
|
||||
// Sign return the odd of z.d
|
||||
func (z *Zp) Sign() uint {
|
||||
return z.Normalize().d.Bit(0)
|
||||
}
|
||||
|
||||
// Equal ...
|
||||
func (z *Zp) Equal(p *Zp) bool {
|
||||
return z.Normalize().d.Cmp(p.Normalize().d) == 0
|
||||
}
|
||||
|
||||
// GetItem return the d, this is for a extension field,
|
||||
// the d is an array, and return the d[i]
|
||||
func (z *Zp) GetItem(i int) *big.Int {
|
||||
if i == 0 {
|
||||
return z.d
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Normalize put d to [0,p-1]
|
||||
func (z *Zp) Normalize() *Zp {
|
||||
z.d.Mod(z.d, z.p)
|
||||
return z
|
||||
}
|
||||
|
||||
// Bytes return the byte slice of z.d, with a const slice size with p.Bytes()
|
||||
func (z *Zp) Bytes() []byte {
|
||||
z.Normalize()
|
||||
return intToByte(z.d, z.byteSize)
|
||||
}
|
||||
|
||||
func (z *Zp) String() string {
|
||||
return hex.EncodeToString(z.Bytes())
|
||||
}
|
||||
|
||||
// Add z = p+q
|
||||
// make sure that z,p,q are in the same field, or the result is a shit
|
||||
func (z *Zp) Add(p, q *Zp) *Zp {
|
||||
pp := p.d
|
||||
qq := q.d
|
||||
z.d.Add(pp, qq)
|
||||
return z
|
||||
}
|
||||
|
||||
// AddInt z = p+n
|
||||
func (z *Zp) AddInt(p *Zp, n int) *Zp {
|
||||
z.d.Add(p.d, big.NewInt(int64(n)))
|
||||
return z
|
||||
}
|
||||
|
||||
// AddBigInt ...
|
||||
func (z *Zp) AddBigInt(p *Zp, n *big.Int) *Zp {
|
||||
z.d.Add(p.d, n)
|
||||
return z
|
||||
}
|
||||
|
||||
// Neg ...
|
||||
func (z *Zp) Neg(p *Zp) *Zp {
|
||||
p.Normalize() // p maybe changed, but not matter
|
||||
if !p.Is0() {
|
||||
z.d.Sub(z.d, p.d)
|
||||
} else {
|
||||
z.Set(p)
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// Sub ...
|
||||
func (z *Zp) Sub(p, q *Zp) *Zp {
|
||||
z.d.Sub(p.d, q.d)
|
||||
return z
|
||||
}
|
||||
|
||||
// SubInt ...
|
||||
func (z *Zp) SubInt(p *Zp, n int) *Zp {
|
||||
z.d.Sub(p.d, big.NewInt(int64(n)))
|
||||
return z
|
||||
}
|
||||
|
||||
// SubBigInt ...
|
||||
func (z *Zp) SubBigInt(p *Zp, n *big.Int) *Zp {
|
||||
z.d.Sub(p.d, n)
|
||||
return z
|
||||
}
|
||||
|
||||
// Mul ...
|
||||
func (z *Zp) Mul(p, q *Zp) *Zp {
|
||||
p.Normalize()
|
||||
q.Normalize()
|
||||
z.d.Mul(p.d, q.d)
|
||||
z.Normalize()
|
||||
return z
|
||||
}
|
||||
|
||||
// MulInt ...
|
||||
func (z *Zp) MulInt(p *Zp, n int) *Zp {
|
||||
z.d.Mul(p.d, big.NewInt(int64(n)))
|
||||
z.Normalize()
|
||||
return z
|
||||
}
|
||||
|
||||
// MulBigInt ...
|
||||
func (z *Zp) MulBigInt(p *Zp, n *big.Int) *Zp {
|
||||
z.d.Mul(p.d, n)
|
||||
z.Normalize()
|
||||
return z
|
||||
}
|
||||
|
||||
// Inv z=p^(-1), if p == 0, panic
|
||||
func (z *Zp) Inv(p *Zp) *Zp {
|
||||
if p.Is0() {
|
||||
panic("zp:Inv try to invert 0")
|
||||
}
|
||||
z.d.ModInverse(p.d, z.p)
|
||||
return z
|
||||
}
|
||||
|
||||
// Random return a random number from entropy
|
||||
func (z *Zp) Random() error {
|
||||
n, err := rand.Int(grand.Reader, z.p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
z.d = n
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
module xdx.jelly/xgcl
|
||||
|
||||
go 1.23
|
||||
|
||||
require (
|
||||
github.com/stretchr/testify v1.8.4
|
||||
golang.org/x/crypto v0.17.0
|
||||
golang.org/x/sys v0.15.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
Package grand is the random number generators.
|
||||
|
||||
Use the following io.Reader to generate random numbers:
|
||||
- grand.Reader, the go's crypto/rand (/dev/urandom in *nix)
|
||||
- grand.SM3Rng, the DRNG of SM3_RNG
|
||||
- grand.SM4Rng, the DRNG of SM4_RNG
|
||||
|
||||
example:
|
||||
|
||||
buf := make([]byte,32)
|
||||
if _, err := grand.SM3Rng.Read(buf);err != nil{
|
||||
//
|
||||
}
|
||||
|
||||
随机数检测相关的xdx.jelly/
|
||||
*/
|
||||
package grand
|
||||
@@ -0,0 +1,38 @@
|
||||
package ctrrng
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
)
|
||||
|
||||
var defaultConfig1 = &internal.DrngConfig{
|
||||
Seedlen: 256 >> 3,
|
||||
Outlen: 128 >> 3,
|
||||
ReseedIntervalInTime: time.Second * 600,
|
||||
ReseedIntervalInCounter: 1 << 20,
|
||||
MinEntropy: 256 >> 3,
|
||||
MinEntropyInputLength: 256 >> 3,
|
||||
MaxEntropyInputLength: (1 << 35) >> 3,
|
||||
}
|
||||
|
||||
var defaultConfig2 = &internal.DrngConfig{
|
||||
Seedlen: 256 >> 3,
|
||||
Outlen: 128 >> 3,
|
||||
ReseedIntervalInTime: time.Second * 60,
|
||||
ReseedIntervalInCounter: 1 << 10,
|
||||
MinEntropy: 256 >> 3,
|
||||
MinEntropyInputLength: 256 >> 3,
|
||||
MaxEntropyInputLength: (1 << 35) >> 3,
|
||||
}
|
||||
|
||||
func Config(level internal.SecureLevel) *internal.DrngConfig {
|
||||
switch level {
|
||||
case internal.SecureLevel1:
|
||||
return defaultConfig1
|
||||
case internal.SecureLevel2:
|
||||
return defaultConfig2
|
||||
default:
|
||||
panic("unsupported secure level")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
package ctrrng
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
"xdx.jelly/xgcl/internal/xor"
|
||||
"xdx.jelly/xgcl/sm/sm4"
|
||||
)
|
||||
|
||||
type SM4BlockNewer struct{}
|
||||
|
||||
func (b SM4BlockNewer) BlockSize() int {
|
||||
return sm4.BlockSize
|
||||
}
|
||||
|
||||
func (b SM4BlockNewer) New(key []byte) cipher.Block {
|
||||
if len(key) != sm4.BlockSize {
|
||||
panic("ctrrng: invalid block key length")
|
||||
}
|
||||
|
||||
block, _ := sm4.NewCipher(key)
|
||||
return block
|
||||
}
|
||||
|
||||
func NewCtrDrng(newBlock NewBlock, config *internal.DrngConfig) (internal.RawDrng, error) {
|
||||
hd := &CtrDrng{
|
||||
config: *config,
|
||||
newBlock: newBlock,
|
||||
df: newDF(newBlock),
|
||||
}
|
||||
|
||||
// 析构时对内部状态置0
|
||||
runtime.SetFinalizer(hd, func(hd *CtrDrng) {
|
||||
hd.state.zeromize()
|
||||
})
|
||||
return hd, nil
|
||||
}
|
||||
|
||||
type internalState struct {
|
||||
v []byte // blockLen
|
||||
k []byte // keyLen
|
||||
|
||||
reseedCounter uint32
|
||||
lastReseedTime time.Time
|
||||
}
|
||||
|
||||
// zeromize 对内部状态置0
|
||||
func (s *internalState) zeromize() {
|
||||
for i := 0; i < len(s.v); i++ {
|
||||
s.v[i] = 0
|
||||
}
|
||||
|
||||
for i := 0; i < len(s.k); i++ {
|
||||
s.k[i] = 0
|
||||
}
|
||||
|
||||
s.reseedCounter = 0
|
||||
}
|
||||
|
||||
type CtrDrng struct {
|
||||
// mu sync.Mutex
|
||||
|
||||
config internal.DrngConfig
|
||||
newBlock NewBlock
|
||||
df func(input []byte, n int) []byte
|
||||
state internalState
|
||||
personalizationString []byte //个性化字符串,来自应用的比特串
|
||||
}
|
||||
|
||||
type NewBlock interface {
|
||||
BlockSize() int
|
||||
New(key []byte) cipher.Block
|
||||
}
|
||||
|
||||
// newDF 返回一个使用block作为杂凑的df函数
|
||||
// 例:SM3_df = newDF(sm.SM3)
|
||||
func newDF(newBlock NewBlock) func(input []byte, n int) []byte {
|
||||
keylen := newBlock.BlockSize()
|
||||
outlen := newBlock.BlockSize()
|
||||
keymatial := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 31}
|
||||
|
||||
return func(input []byte, n int) []byte {
|
||||
L := len(input)
|
||||
|
||||
// S = L || n || input || 0x80 || 00 such that len(S) % n = 0
|
||||
S := make([]byte, ((9+L+n-1)/n)*n)
|
||||
binary.BigEndian.PutUint32(S, uint32(L))
|
||||
binary.BigEndian.PutUint32(S[4:], uint32(n))
|
||||
copy(S[8:], input)
|
||||
S[8+L] = 0x80
|
||||
|
||||
K := keymatial[:keylen]
|
||||
temp := make([]byte, 0, keylen+n)
|
||||
ivs := make([]byte, outlen+len(S)) // iv || S
|
||||
copy(ivs[4:], S)
|
||||
i := uint32(0)
|
||||
block := newBlock.New(K)
|
||||
for len(temp) < keylen+n {
|
||||
binary.BigEndian.PutUint32(ivs, i)
|
||||
i++
|
||||
temp = append(temp, cbcMac(block, ivs)...)
|
||||
}
|
||||
|
||||
K = temp[:keylen]
|
||||
X := temp[keylen:]
|
||||
block = newBlock.New(K)
|
||||
temp = []byte{}
|
||||
for len(temp) < n {
|
||||
block.Encrypt(X, X)
|
||||
temp = append(temp, X...)
|
||||
}
|
||||
return temp[:n]
|
||||
}
|
||||
}
|
||||
|
||||
// len(data) % block.BlockSize() == 0
|
||||
func cbcMac(block cipher.Block, data []byte) []byte {
|
||||
blockSize := block.BlockSize()
|
||||
iv := make([]byte, blockSize)
|
||||
n := 0
|
||||
for n+blockSize <= len(data) {
|
||||
xor.XorBytes(iv, iv, data[n:])
|
||||
block.Encrypt(iv, iv)
|
||||
n += blockSize
|
||||
}
|
||||
return iv
|
||||
}
|
||||
|
||||
func (cd *CtrDrng) keyLen() int {
|
||||
return cd.newBlock.BlockSize()
|
||||
}
|
||||
|
||||
func (cd *CtrDrng) blockLen() int {
|
||||
return cd.newBlock.BlockSize()
|
||||
}
|
||||
|
||||
func (cd *CtrDrng) seedLen() int {
|
||||
return cd.keyLen() + cd.OutLen()
|
||||
}
|
||||
|
||||
func (cd *CtrDrng) OutLen() int {
|
||||
return cd.config.Outlen
|
||||
}
|
||||
|
||||
func (cd *CtrDrng) Config() *internal.DrngConfig {
|
||||
return &cd.config
|
||||
}
|
||||
|
||||
// Instantiate 初始化HashDrng
|
||||
func (cd *CtrDrng) Instantiate(personalizationString []byte, nonce []byte, entropySource io.Reader) (internal.Drng, error) {
|
||||
// cd.mu.Lock()
|
||||
// defer cd.mu.Unlock()
|
||||
|
||||
cfg := cd.config
|
||||
cd.personalizationString = personalizationString
|
||||
cd.state.k = make([]byte, cd.keyLen())
|
||||
cd.state.v = make([]byte, cd.blockLen())
|
||||
|
||||
seedMaterial := make([]byte, 2*cfg.MinEntropyInputLength, int(2*cfg.MinEntropyInputLength)+len(nonce)+len(personalizationString))
|
||||
var m, n int
|
||||
var err error
|
||||
var errCount int
|
||||
for n < int(cfg.MinEntropyInputLength) {
|
||||
m, err = entropySource.Read(seedMaterial[n:])
|
||||
n += m
|
||||
if err != nil {
|
||||
errCount++
|
||||
}
|
||||
if errCount > 3 {
|
||||
return cd, err
|
||||
}
|
||||
}
|
||||
seedMaterial = append(seedMaterial, nonce...)
|
||||
seedMaterial = append(seedMaterial, personalizationString...)
|
||||
seedMaterial = cd.df(seedMaterial, cd.seedLen())
|
||||
cd.update(seedMaterial)
|
||||
return cd, nil
|
||||
}
|
||||
|
||||
func (cd *CtrDrng) update(seedMaterial []byte) {
|
||||
seedlen := cd.seedLen()
|
||||
temp := make([]byte, seedlen)
|
||||
n := 0
|
||||
block := cd.newBlock.New(cd.state.k)
|
||||
for n+cd.blockLen() < seedlen {
|
||||
internal.IncBytes(cd.state.v)
|
||||
block.Encrypt(temp[n:n+cd.blockLen()], cd.state.v)
|
||||
n += cd.blockLen()
|
||||
}
|
||||
xor.XorBytes(temp, temp, seedMaterial)
|
||||
copy(cd.state.k, temp)
|
||||
copy(cd.state.v, temp[cd.keyLen():])
|
||||
}
|
||||
|
||||
func (cd *CtrDrng) Reseed(entropyInput, additionalInput []byte) {
|
||||
// cd.mu.Lock()
|
||||
// defer cd.mu.Unlock()
|
||||
|
||||
seedMaterial := make([]byte, len(entropyInput)+len(additionalInput))
|
||||
copy(seedMaterial, entropyInput)
|
||||
copy(seedMaterial[len(entropyInput):], additionalInput)
|
||||
seedMaterial = cd.df(seedMaterial, cd.seedLen())
|
||||
cd.update(seedMaterial)
|
||||
cd.state.reseedCounter = 1
|
||||
cd.state.lastReseedTime = time.Now()
|
||||
for i := 0; i < len(seedMaterial); i++ {
|
||||
seedMaterial[i] = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (cd *CtrDrng) Generate(b []byte, additionalInput []byte) error {
|
||||
// cd.mu.Lock()
|
||||
// defer cd.mu.Unlock()
|
||||
|
||||
if len(b) > cd.config.Outlen {
|
||||
return internal.ErrReturnedBitsTooLong
|
||||
}
|
||||
|
||||
// 需要重播种
|
||||
if cd.state.reseedCounter > uint32(cd.config.ReseedIntervalInCounter) ||
|
||||
time.Since(cd.state.lastReseedTime) > cd.config.ReseedIntervalInTime {
|
||||
return internal.ErrNeedReseed
|
||||
}
|
||||
|
||||
if len(additionalInput) > 0 {
|
||||
additionalInput = cd.df(additionalInput, cd.seedLen())
|
||||
cd.update(additionalInput)
|
||||
} else {
|
||||
additionalInput = make([]byte, cd.seedLen())
|
||||
}
|
||||
block := cd.newBlock.New(cd.state.k)
|
||||
internal.IncBytes(cd.state.v)
|
||||
outputBlock := make([]byte, block.BlockSize())
|
||||
block.Encrypt(outputBlock, cd.state.v)
|
||||
copy(b, outputBlock)
|
||||
cd.update(additionalInput)
|
||||
cd.state.reseedCounter++
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package ctrrng
|
||||
|
||||
import (
|
||||
_ "crypto/sha256"
|
||||
)
|
||||
|
||||
// func TestSm4CtrDrng(t *testing.T) {
|
||||
// rnd := make([]byte, 1280)
|
||||
// _, _ = Reader.Read(rnd)
|
||||
// fmt.Printf("%x\n", rnd)
|
||||
// }
|
||||
|
||||
// func TestSm4DrngRandomness(t *testing.T) {
|
||||
// // 测试Sm4Drng的随机性测试通过率
|
||||
// total := 10
|
||||
// pass := 0
|
||||
// for i := 0; i < total; i++ {
|
||||
// fmt.Println("======================================", i)
|
||||
// if statistics.SampleSelfTests(Reader) {
|
||||
// fmt.Printf("%d-th test: [O]\n", i)
|
||||
// pass += 1
|
||||
// } else {
|
||||
// fmt.Printf("%d-th test: [X]\n", i)
|
||||
// }
|
||||
// }
|
||||
|
||||
// fmt.Printf("Pass Rate: %d/%d\n", pass, total)
|
||||
// }
|
||||
@@ -0,0 +1,100 @@
|
||||
// package drng implements the SM3Rng and SM4Rng which specified in GM/T 0115.
|
||||
//
|
||||
// ctrrng and hashrng implements the low-level Drng interface.
|
||||
// Combine entropy(pool) and xxxrng we got the Drng as a ReadWriter.
|
||||
// The Read method generates random bits, and the Write method
|
||||
// add outter entropy into the Drng.
|
||||
//
|
||||
// Use drng.SM3Rng as an ordinary io.Reader to generate random bits.
|
||||
// If necessary, it could add extra entropy into the Drng.
|
||||
// For example, add user's scratch points on mobile, get random bits
|
||||
// from the cryptography server, etc..
|
||||
package drng
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/ctrrng"
|
||||
"xdx.jelly/xgcl/grand/drng/entropy"
|
||||
"xdx.jelly/xgcl/grand/drng/hashrng"
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
"xdx.jelly/xgcl/sm"
|
||||
)
|
||||
|
||||
// PERSONALIZATIONSTRING = "粤信签协同签名软件Android客户端密码模块YXQXTQM-Y"
|
||||
var PERSONALIZATIONSTRING = []byte("xdx")
|
||||
|
||||
// SM3Rng implements the io.ReadWriter interface.
|
||||
//
|
||||
// SM3Rng.Read reads random bytes from the DRNG.
|
||||
// SM3rng.Write add extra entropy to the DRNG.
|
||||
var SM3Rng io.ReadWriter
|
||||
var SM4Rng io.ReadWriter
|
||||
|
||||
func init() {
|
||||
raw, _ := hashrng.NewHashDrng(sm.SM3, hashrng.Config(internal.SecureLevel2))
|
||||
rng, _ := raw.Instantiate(PERSONALIZATIONSTRING, internal.Nonce(), entropy.GetEntropyPool())
|
||||
SM3Rng = &DrngUtil{
|
||||
Drng: rng,
|
||||
ReseedSource: entropy.GetEntropyPool(),
|
||||
}
|
||||
|
||||
raw, _ = ctrrng.NewCtrDrng(ctrrng.SM4BlockNewer{}, ctrrng.Config(internal.SecureLevel2))
|
||||
rng, _ = raw.Instantiate(PERSONALIZATIONSTRING, internal.Nonce(), entropy.GetEntropyPool())
|
||||
SM4Rng = &DrngUtil{
|
||||
Drng: rng,
|
||||
ReseedSource: entropy.GetEntropyPool(),
|
||||
}
|
||||
}
|
||||
|
||||
// DrngUtil implements the io.Reader interface
|
||||
type DrngUtil struct {
|
||||
mu sync.Mutex
|
||||
internal.Drng
|
||||
ReseedSource io.Reader // 重播种熵源
|
||||
|
||||
additionalInput io.Reader // TODO: 额外输入, 可为空
|
||||
}
|
||||
|
||||
// Write implements io.ReadWriter.
|
||||
// The returns can be ignored.
|
||||
func (du *DrngUtil) Write(p []byte) (n int, err error) {
|
||||
du.mu.Lock()
|
||||
defer du.mu.Unlock()
|
||||
|
||||
du.Drng.Reseed(p, nil)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Read implements io.Reader
|
||||
func (du *DrngUtil) Read(p []byte) (n int, err error) {
|
||||
du.mu.Lock()
|
||||
defer du.mu.Unlock()
|
||||
|
||||
outlen := du.OutLen()
|
||||
for len(p) > 0 {
|
||||
generateLen := len(p)
|
||||
if generateLen > outlen {
|
||||
generateLen = outlen
|
||||
}
|
||||
err := du.Generate(p[:generateLen], nil)
|
||||
if err != nil {
|
||||
// 需要重播种
|
||||
config := du.Config()
|
||||
entropyInput := make([]byte, config.MinEntropy)
|
||||
n, err := du.ReseedSource.Read(entropyInput)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
du.Drng.Reseed(entropyInput[:n], nil)
|
||||
err = du.Generate(p[:generateLen], nil)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
n += generateLen
|
||||
p = p[generateLen:]
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package drng_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xdx.jelly/xgcl/grand/drng"
|
||||
)
|
||||
|
||||
// 0.03GBps, 主要是internal.Outlen太小
|
||||
func TestSM3RngSpeed(t *testing.T) {
|
||||
data := make([]byte, 10*1024*1024)
|
||||
|
||||
start := time.Now()
|
||||
times := 10
|
||||
for i := 0; i < times; i++ {
|
||||
_, err := drng.SM3Rng.Read(data)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
end := time.Now()
|
||||
elapsed := end.Sub(start)
|
||||
t.Logf("Generate Random speed: %.2f MBps\n", float64(times*len(data))/float64(1024*1024)/elapsed.Seconds())
|
||||
}
|
||||
|
||||
func TestSM4RngSpeed(t *testing.T) {
|
||||
data := make([]byte, 10*1024*1024)
|
||||
|
||||
start := time.Now()
|
||||
times := 10
|
||||
for i := 0; i < times; i++ {
|
||||
_, err := drng.SM4Rng.Read(data)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
end := time.Now()
|
||||
elapsed := end.Sub(start)
|
||||
t.Logf("Generate Random speed: %.2f MBps\n", float64(times*len(data))/float64(1024*1024)/elapsed.Seconds())
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package cpu
|
||||
|
||||
//go:noescape
|
||||
func cpuid() uint64
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "textflag.h"
|
||||
|
||||
// __asm__("mrs %0, MIDR_EL1" : "=r"(arm_cpuid));
|
||||
TEXT ·cpuid(SB), NOSPLIT, $0
|
||||
MRS MIDR_EL1, R0
|
||||
MOVD R0, res+0(FP)
|
||||
RET
|
||||
@@ -0,0 +1,10 @@
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCPUID(t *testing.T) {
|
||||
fmt.Println(cpuid())
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package entropy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
func MarkovTests(data []byte, verbose bool) float64 {
|
||||
// 将data转换为0,1比特串表示
|
||||
epsilon := make([]byte, 0, len(data)*8)
|
||||
for _, b := range data {
|
||||
epsilon = append(epsilon, (b>>7)&1)
|
||||
epsilon = append(epsilon, (b>>6)&1)
|
||||
epsilon = append(epsilon, (b>>5)&1)
|
||||
epsilon = append(epsilon, (b>>4)&1)
|
||||
epsilon = append(epsilon, (b>>3)&1)
|
||||
epsilon = append(epsilon, (b>>2)&1)
|
||||
epsilon = append(epsilon, (b>>1)&1)
|
||||
epsilon = append(epsilon, (b>>0)&1)
|
||||
}
|
||||
|
||||
// double markov_test(byte* data, long len, const int verbose, const char *label){
|
||||
var i, C_0, C_1, C_00, C_10 int64
|
||||
var H_min, tmp_min_entropy, P_0, P_1, P_00, P_01, P_10, P_11, entEst float64
|
||||
|
||||
C_0 = 0
|
||||
C_00 = 0
|
||||
C_10 = 0
|
||||
dataLen := int64(len(epsilon))
|
||||
// get counts for unconditional and transition probabilities
|
||||
for i = 0; i < dataLen-1; i++ {
|
||||
if epsilon[i] == 0 {
|
||||
C_0++
|
||||
if epsilon[i+1] == 0 {
|
||||
C_00++
|
||||
}
|
||||
} else if epsilon[i+1] == 0 {
|
||||
C_10++
|
||||
}
|
||||
}
|
||||
|
||||
//C_0 is now the number of 0 bits from S[0] to S[len-2]
|
||||
|
||||
C_1 = dataLen - 1 - C_0 //C_1 is the number of 1 bits from S[0] to S[len-2]
|
||||
|
||||
//Note that P_X1 = C_X1 / C_X = (C_X - C_X0)/C_X = 1.0 - C_X0/C_X = 1.0 - P_X0
|
||||
if C_0 > 0 {
|
||||
P_00 = float64(C_00) / float64(C_0)
|
||||
P_01 = 1.0 - P_00
|
||||
} else {
|
||||
P_00 = 0.0
|
||||
P_01 = 0.0
|
||||
}
|
||||
|
||||
if C_1 > 0 {
|
||||
P_10 = float64(C_10) / float64(C_1)
|
||||
P_11 = 1.0 - P_10
|
||||
} else {
|
||||
P_10 = 0.0
|
||||
P_11 = 0.0
|
||||
}
|
||||
|
||||
// account for the last symbol
|
||||
if epsilon[dataLen-1] == 0 {
|
||||
C_0++
|
||||
}
|
||||
//C_0 is now the number of 0 bits from S[0] to S[len-1]
|
||||
|
||||
P_0 = float64(C_0) / float64(dataLen)
|
||||
P_1 = 1.0 - P_0
|
||||
|
||||
if verbose {
|
||||
fmt.Printf("P_0 = %.17g\n", P_0)
|
||||
fmt.Printf("P_1 = %.17g\n", P_1)
|
||||
fmt.Printf("P_{0,0} = %.17g\n", P_00)
|
||||
fmt.Printf("P_{0,1} = %.17g\n", P_01)
|
||||
fmt.Printf("P_{1,0} = %.17g\n", P_10)
|
||||
fmt.Printf("P_{1,1} = %.17g\n", P_11)
|
||||
}
|
||||
|
||||
H_min = 128.0
|
||||
|
||||
//In the next block, note that if P_0X > 0.0, then P_0 > 0.0
|
||||
//and similarly if P_1X > 0.0, then P_1 > 0.0
|
||||
|
||||
// Sequence 00...0
|
||||
if P_00 > 0.0 {
|
||||
tmp_min_entropy = -math.Log2(P_0) - 127.0*math.Log2(P_00)
|
||||
if tmp_min_entropy < H_min {
|
||||
H_min = tmp_min_entropy
|
||||
}
|
||||
}
|
||||
|
||||
// Sequence 0101...01
|
||||
if (P_01 > 0.0) && (P_10 > 0.0) {
|
||||
tmp_min_entropy = -math.Log2(P_0) - 64.0*math.Log2(P_01) - 63.0*math.Log2(P_10)
|
||||
if tmp_min_entropy < H_min {
|
||||
H_min = tmp_min_entropy
|
||||
}
|
||||
}
|
||||
|
||||
// Sequence 011...1
|
||||
if (P_01 > 0.0) && (P_11 > 0.0) {
|
||||
tmp_min_entropy = -math.Log2(P_0) - math.Log2(P_01) - 126.0*math.Log2(P_11)
|
||||
if tmp_min_entropy < H_min {
|
||||
H_min = tmp_min_entropy
|
||||
}
|
||||
}
|
||||
|
||||
// Sequence 100...0
|
||||
if (P_10 > 0.0) && (P_00 > 0.0) {
|
||||
tmp_min_entropy = -math.Log2(P_1) - math.Log2(P_10) - 126.0*math.Log2(P_00)
|
||||
if tmp_min_entropy < H_min {
|
||||
H_min = tmp_min_entropy
|
||||
}
|
||||
}
|
||||
|
||||
// Sequence 1010...10
|
||||
if (P_10 > 0.0) && (P_01 > 0.0) {
|
||||
tmp_min_entropy = -math.Log2(P_1) - 64.0*math.Log2(P_10) - 63.0*math.Log2(P_01)
|
||||
if tmp_min_entropy < H_min {
|
||||
H_min = tmp_min_entropy
|
||||
}
|
||||
}
|
||||
|
||||
// Sequence 11...1
|
||||
if P_11 > 0.0 {
|
||||
tmp_min_entropy = -math.Log2(P_1) - 127.0*math.Log2(P_11)
|
||||
if tmp_min_entropy < H_min {
|
||||
H_min = tmp_min_entropy
|
||||
}
|
||||
}
|
||||
|
||||
entEst = math.Min(H_min/128.0, 1.0)
|
||||
|
||||
if verbose {
|
||||
fmt.Printf("p_max = %.17g\n", math.Pow(2.0, -H_min))
|
||||
fmt.Printf("min entropy = %.17g\n", entEst)
|
||||
}
|
||||
|
||||
return entEst
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package entropy
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
)
|
||||
|
||||
var OutOfEntropyErr = errors.New("out of entropy")
|
||||
|
||||
// Read reads at most 32 bytes into p.
|
||||
// For efficiency, reads bytes are always multiples of 4.
|
||||
func (e *EntropyPool) Read(p []byte) (int, error) {
|
||||
entropyPool.mu.Lock()
|
||||
|
||||
if entropyPool.entropySize <= 0 {
|
||||
return 0, OutOfEntropyErr
|
||||
}
|
||||
// n = min(8, entropyPool.entropySize, len(p) / 4)
|
||||
n := 8
|
||||
if entropyPool.entropySize < 8 {
|
||||
n = entropyPool.entropySize
|
||||
}
|
||||
|
||||
if (len(p) / 4) < n {
|
||||
n = len(p) / 4
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
x, _ := entropyPool.get() // err should not happen
|
||||
binary.BigEndian.PutUint32(p[4*i:], x)
|
||||
}
|
||||
|
||||
entropyPool.mu.Unlock()
|
||||
|
||||
go e.update() // update the entropy pool for next reading.
|
||||
|
||||
return 4 * n, nil
|
||||
}
|
||||
|
||||
// EntropyPool 系统熵池
|
||||
type EntropyPool struct {
|
||||
mu sync.Mutex //使用互斥锁保证独占性
|
||||
pool [128]uint32 //熵池,128个字(512字节)
|
||||
// i - j 之间是未取的熵(mod 128)
|
||||
i int //熵索引开始
|
||||
j int //熵索引结束
|
||||
entropySize int //熵池中可用熵值
|
||||
source []EntropySource
|
||||
}
|
||||
|
||||
// entropySource 熵源
|
||||
type EntropySource interface {
|
||||
GetEntropy(minEntropy int64, minEntropyInputLength int64, maxEntropyInputLength int64) ([]byte, error)
|
||||
}
|
||||
|
||||
var entropyPool *EntropyPool
|
||||
var initEntropyPool sync.Once
|
||||
|
||||
func init() {
|
||||
initEntropyPool.Do(
|
||||
func() {
|
||||
entropyPool = newEntropyPool()
|
||||
})
|
||||
go func() {
|
||||
// 定时从系统中获取
|
||||
tickle := time.NewTicker(10 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-tickle.C:
|
||||
entropyPool.update()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func GetEntropyPool() *EntropyPool {
|
||||
return entropyPool
|
||||
}
|
||||
|
||||
func newEntropyPool() *EntropyPool {
|
||||
// FIXME: SysTimeEntropySource?
|
||||
p := &EntropyPool{
|
||||
source: []EntropySource{&OSEntropySource{}, &SysTimeEntropySource{}},
|
||||
// source: []drng.EntropySource{&OSEntropySource{}},
|
||||
}
|
||||
|
||||
buf := make([]byte, 128*4)
|
||||
_, _ = rand.Reader.Read(buf)
|
||||
for i := 0; i < 128; i++ {
|
||||
p.pool[i] = binary.BigEndian.Uint32(buf[4*i:])
|
||||
}
|
||||
|
||||
// 从每个熵源获取至少256比特
|
||||
p.update()
|
||||
|
||||
// 对buf置0
|
||||
for i := range buf {
|
||||
buf[i] = 0
|
||||
}
|
||||
// for i := range e {
|
||||
// e[i] = 0
|
||||
// }
|
||||
return p
|
||||
}
|
||||
|
||||
func (e *EntropyPool) get() (uint32, error) {
|
||||
if e.entropySize <= 0 {
|
||||
return 0, OutOfEntropyErr
|
||||
}
|
||||
n := e.pool[e.i]
|
||||
e.i = (e.i + 1) & 127
|
||||
e.entropySize--
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// lshr 添加新的熵数据g到熵池中。按照GM/T 0105 A.3的方式
|
||||
func (e *EntropyPool) lshr(g uint32) {
|
||||
var table = [8]uint32{0, 0x3b6e20c8, 0x76dc4190, 0x4db26158, 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278}
|
||||
temp := g ^ e.pool[e.j]
|
||||
for _, i := range []int{1, 25, 51, 76, 103} {
|
||||
temp ^= e.pool[(e.j+i)&127]
|
||||
}
|
||||
temp = (temp >> 3) ^ table[temp&7]
|
||||
e.pool[e.j] = temp
|
||||
e.j = (e.j + 1) & 127
|
||||
|
||||
// 置0
|
||||
temp = 0
|
||||
_ = temp
|
||||
}
|
||||
|
||||
// Update 熵池更新
|
||||
func (e *EntropyPool) update() {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
// 设置超时时间
|
||||
tickle := time.NewTicker(100 * time.Millisecond)
|
||||
defer tickle.Stop()
|
||||
|
||||
for i := 0; e.entropySize < 128; i = (i + 1) % len(e.source) {
|
||||
select {
|
||||
case <-tickle.C:
|
||||
break
|
||||
default:
|
||||
s := e.source[i]
|
||||
b, _ := s.GetEntropy(4, 4, internal.MaxEntropyInputLength)
|
||||
if len(b) >= 4 {
|
||||
e.lshr(binary.BigEndian.Uint32(b))
|
||||
e.entropySize++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EntropyPool) GetEntropy(minEntropy int64, minEntropyInputLength int64, maxEntropyInputLength int64) ([]byte, error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
if minEntropyInputLength < internal.MinEntropyInputLength || maxEntropyInputLength > internal.MaxEntropyInputLength {
|
||||
return nil, internal.ErrEntropyLength
|
||||
}
|
||||
|
||||
entropy := make([]byte, minEntropyInputLength)
|
||||
buf := make([]byte, 4)
|
||||
var i int
|
||||
for i = 0; int64(i) < minEntropyInputLength && e.entropySize > 0; i += 4 {
|
||||
binary.BigEndian.PutUint32(buf, e.pool[e.i])
|
||||
copy(entropy[i:], buf)
|
||||
e.i = (e.i + 1) & 127
|
||||
e.entropySize--
|
||||
}
|
||||
return entropy[:i], nil
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package entropy
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type OSEntropySource struct {
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (e *OSEntropySource) GetEntropy(minEntropy int64, minEntropyInputLength int64, maxEntropyInputLength int64) ([]byte, error) {
|
||||
//使用互斥锁保证熵源的独占性
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
n := minEntropy
|
||||
if n < minEntropyInputLength {
|
||||
n = minEntropyInputLength
|
||||
}
|
||||
entropy := make([]byte, n)
|
||||
if _, err := rand.Reader.Read(entropy); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return entropy, nil
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package entropy
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/entropy/rdtsc"
|
||||
)
|
||||
|
||||
// SysTimeEntropySource 系统时间熵源
|
||||
type SysTimeEntropySource struct {
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// GetEntropy
|
||||
func (e *SysTimeEntropySource) GetEntropy(minEntropy int64, minEntropyInputLength int64, maxEntropyInputLength int64) ([]byte, error) {
|
||||
//使用互斥锁保证熵源的独占性
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
// SysTimeEntropySource熵源的Markov测试min entropy ~ 0.58
|
||||
// 因此向熵源最少要取minEntropy / 0.58 ~ 2*minEntropy
|
||||
n := minEntropy << 1
|
||||
if n < minEntropyInputLength {
|
||||
n = minEntropyInputLength
|
||||
}
|
||||
entropy := make([]byte, n)
|
||||
for i := int64(0); i < n; i++ {
|
||||
// var b byte
|
||||
// for j := 0; j < 8; j++ {
|
||||
// t := rdtsc.GetCPUTimeStamp()
|
||||
// // xor of the the last two bits are used.
|
||||
// // for a rdtsc usually used 20~50 cycles.
|
||||
// // b |= byte((t^(t>>1)^(t>>2)^(t>>3))&1) << j
|
||||
// b |= byte(t&1) << j
|
||||
// }
|
||||
// entropy[i] = b
|
||||
|
||||
entropy[i] = byte(rdtsc.GetCPUTimeStamp())
|
||||
}
|
||||
return entropy, nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package entropy
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMarkovSimple(t *testing.T) {
|
||||
data := []byte{0b10001110, 0b01010101, 0b11001100, 0b01110010, 0b10101110}
|
||||
h := MarkovTests(data, false)
|
||||
if h-0.761 > 0.01 {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarkov(t *testing.T) {
|
||||
// 系统熵源
|
||||
// entropy := OSEntropySource{}
|
||||
entropy := SysTimeEntropySource{}
|
||||
data, _ := entropy.GetEntropy(1000000/8, 1000000/8, 1000000/8)
|
||||
MarkovTests(data, false)
|
||||
}
|
||||
|
||||
func TestEntropyPoll(t *testing.T) {
|
||||
pool := &EntropyPool{}
|
||||
for i := 0; i < 100; i++ {
|
||||
pool.lshr(0)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
TEXT ·RDSeed(SB), NOSPLIT, $0
|
||||
MRS RNDR, R0
|
||||
MOVD R0, res+0(FP)
|
||||
RET
|
||||
@@ -0,0 +1,9 @@
|
||||
//go:build amd64 || arm64
|
||||
// +build amd64 arm64
|
||||
|
||||
package rdseed
|
||||
|
||||
const SupportRDSEED = true
|
||||
|
||||
//go:noescape
|
||||
func RDSeed() uint64
|
||||
@@ -0,0 +1,12 @@
|
||||
package rdseed
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRDSEED(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
fmt.Printf("%x\n", RDSeed())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
# In linux
|
||||
```
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static long long GetThreadCpuTimeNs() {
|
||||
struct timespec t;
|
||||
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t)) {
|
||||
perror("clock_gettime");
|
||||
return 0;
|
||||
}
|
||||
return t.tv_nsec;
|
||||
}
|
||||
```
|
||||
Makov测试熵估计0.5-0.6
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
TEXT ·GetCPUTimeStamp(SB), NOSPLIT, $0
|
||||
RDTSCP // save time stamp counter in DX:AX
|
||||
SHLQ $32, DX
|
||||
ORQ DX, AX
|
||||
MOVQ AX, res+0(FP)
|
||||
RET
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
TEXT ·GetCPUTimeStamp(SB), NOSPLIT, $0
|
||||
MRS CNTVCT_EL0, R0
|
||||
MOVD R0, res+0(FP)
|
||||
RET
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
//go:build amd64 || arm64
|
||||
// +build amd64 arm64
|
||||
|
||||
package rdtsc
|
||||
|
||||
const SupportRDTSC = true
|
||||
|
||||
//go:noescape
|
||||
func GetCPUTimeStamp() uint64
|
||||
@@ -0,0 +1,9 @@
|
||||
//go:build !amd64 && !arm64
|
||||
|
||||
package rdtsc
|
||||
|
||||
const SupportRDTSC = false
|
||||
|
||||
func GetCPUTimeStamp() uint64 {
|
||||
panic("unsupported")
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package rdtsc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRDTSC(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
fmt.Printf("%x\n", GetCPUTimeStamp())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package hashrng
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
)
|
||||
|
||||
var defaultConfig1 = &internal.DrngConfig{
|
||||
Seedlen: 440 >> 3,
|
||||
Outlen: 256 >> 3,
|
||||
ReseedIntervalInTime: time.Second * 600,
|
||||
ReseedIntervalInCounter: 1 << 20,
|
||||
MinEntropy: 256 >> 3,
|
||||
MinEntropyInputLength: 256 >> 3,
|
||||
MaxEntropyInputLength: (1 << 35) >> 3,
|
||||
}
|
||||
|
||||
// 安全级别2的配置
|
||||
var defaultConfig2 = &internal.DrngConfig{
|
||||
Seedlen: 440 >> 3,
|
||||
Outlen: 256 >> 3,
|
||||
ReseedIntervalInTime: time.Second * 60,
|
||||
ReseedIntervalInCounter: 1 << 10,
|
||||
MinEntropy: 256 >> 3,
|
||||
MinEntropyInputLength: 256 >> 3,
|
||||
MaxEntropyInputLength: (1 << 35) >> 3,
|
||||
}
|
||||
|
||||
func Config(level internal.SecureLevel) *internal.DrngConfig {
|
||||
switch level {
|
||||
case internal.SecureLevel1:
|
||||
return defaultConfig1
|
||||
case internal.SecureLevel2:
|
||||
return defaultConfig2
|
||||
default:
|
||||
panic("unsupported secure level")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
package hashrng
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
|
||||
"xdx.jelly/xgcl/sm"
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
)
|
||||
|
||||
var _ = sm3.BlockSize // import sm3
|
||||
|
||||
// 内部状态
|
||||
type internalState struct {
|
||||
v []byte
|
||||
c []byte
|
||||
|
||||
reseedCounter uint32
|
||||
lastReseedTime time.Time
|
||||
}
|
||||
|
||||
// zeromize 对内部状态置0
|
||||
func (s *internalState) zeromize() {
|
||||
for i := 0; i < len(s.v); i++ {
|
||||
s.v[i] = 0
|
||||
}
|
||||
|
||||
for i := 0; i < len(s.c); i++ {
|
||||
s.c[i] = 0
|
||||
}
|
||||
|
||||
s.reseedCounter = 0
|
||||
}
|
||||
|
||||
type HashDrng struct {
|
||||
// mu sync.Mutex
|
||||
config internal.DrngConfig
|
||||
hash sm.Hash
|
||||
df func(input []byte, n int) []byte
|
||||
state internalState
|
||||
personalizationString []byte //个性化字符串,来自应用的比特串
|
||||
}
|
||||
|
||||
// Read implements internal.internal.
|
||||
// func (hd *HashDrng) Read(p []byte) (n int, err error) {
|
||||
// return len(p), hd.Generate(p, nil)
|
||||
// }
|
||||
|
||||
// var SM3_df = newDF(sm.SM3)
|
||||
|
||||
// newDF 返回一个使用hash作为杂凑的df函数
|
||||
// 例:SM3_df = newDF(sm.SM3)
|
||||
func newDF(hash sm.Hash) func(input []byte, n int) []byte {
|
||||
h := hash.New()
|
||||
return func(input []byte, n int) []byte {
|
||||
out := make([]byte, 0, n+hash.Size()-1)
|
||||
len := (n + hash.Size() - 1) / hash.Size()
|
||||
counter := uint32(1)
|
||||
buf := make([]byte, 8)
|
||||
for i := 0; i < len; i++ {
|
||||
binary.BigEndian.PutUint32(buf, counter)
|
||||
binary.BigEndian.PutUint32(buf[4:], uint32(n<<3))
|
||||
h.Write(buf)
|
||||
h.Write(input)
|
||||
out = h.Sum(out)
|
||||
h.Reset()
|
||||
counter += 1
|
||||
}
|
||||
return out[:n]
|
||||
}
|
||||
}
|
||||
|
||||
// func New(hash sm.Hash, config *internal.DrngConfig) (internal.Drng, error) {
|
||||
// raw, _ := NewHashDrng(hash, config)
|
||||
// pool := entropy.GetEntropyPool()
|
||||
// d, err := raw.Instantiate([]byte(internal.PERSONALIZATIONSTRING), internal.Nonce(), pool)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return &drng.DrngUtil{
|
||||
// Drng: d,
|
||||
// ReseedSource: pool,
|
||||
// }, nil
|
||||
// }
|
||||
|
||||
func NewHashDrng(hash sm.Hash, config *internal.DrngConfig) (internal.RawDrng, error) {
|
||||
hd := &HashDrng{
|
||||
hash: hash,
|
||||
df: newDF(hash),
|
||||
config: *config,
|
||||
}
|
||||
|
||||
// HashDrng 析构时对内部状态置0
|
||||
runtime.SetFinalizer(hd, func(hd *HashDrng) {
|
||||
hd.state.zeromize()
|
||||
})
|
||||
return hd, nil
|
||||
}
|
||||
|
||||
func (hd *HashDrng) OutLen() int {
|
||||
return hd.config.Outlen
|
||||
}
|
||||
|
||||
func (hd *HashDrng) Config() *internal.DrngConfig {
|
||||
return &hd.config
|
||||
}
|
||||
|
||||
// Instantiate 初始化HashDrng
|
||||
func (hd *HashDrng) Instantiate(personalizationString []byte, nonce []byte, entropySource io.Reader) (internal.Drng, error) {
|
||||
// hd.mu.Lock()
|
||||
// defer hd.mu.Unlock()
|
||||
|
||||
cfg := hd.config
|
||||
hd.personalizationString = personalizationString
|
||||
|
||||
seedMaterial := make([]byte, 2*cfg.MinEntropyInputLength, int(2*cfg.MinEntropyInputLength)+len(nonce)+len(personalizationString))
|
||||
var m, n int
|
||||
var err error
|
||||
var errCount int
|
||||
for n < int(cfg.MinEntropyInputLength) {
|
||||
m, err = entropySource.Read(seedMaterial[n:])
|
||||
n += m
|
||||
if err != nil {
|
||||
errCount++
|
||||
}
|
||||
if errCount > 3 {
|
||||
return hd, err
|
||||
}
|
||||
}
|
||||
seedMaterial = append(seedMaterial, nonce...)
|
||||
seedMaterial = append(seedMaterial, personalizationString...)
|
||||
seed := hd.df(seedMaterial, cfg.Seedlen)
|
||||
|
||||
//初始化内部状态变量
|
||||
hd.state.v = append(hd.state.v[:0], seed...)
|
||||
hd.state.c = append(hd.state.c[:0], hd.df(append([]byte{0}, seed...), cfg.Seedlen)...)
|
||||
hd.state.reseedCounter = 1
|
||||
hd.state.lastReseedTime = time.Now()
|
||||
|
||||
// seed和seedMaterial置0
|
||||
for i := 0; i < len(seed); i++ {
|
||||
seed[i] = 0
|
||||
}
|
||||
for i := 0; i < len(seedMaterial); i++ {
|
||||
seedMaterial[i] = 0
|
||||
}
|
||||
return hd, nil
|
||||
}
|
||||
|
||||
// Reseed 更新HashDrng的内部状态
|
||||
func (hd *HashDrng) Reseed(entropyInput, additionalInput []byte) {
|
||||
// hd.mu.Lock()
|
||||
// defer hd.mu.Unlock()
|
||||
|
||||
seedMaterial := make([]byte, 1, 1+len(entropyInput)+len(hd.state.v)+len(additionalInput))
|
||||
seedMaterial[0] = 1
|
||||
seedMaterial = append(seedMaterial, entropyInput...)
|
||||
seedMaterial = append(seedMaterial, hd.state.v...)
|
||||
seedMaterial = append(seedMaterial, additionalInput...)
|
||||
|
||||
seed := hd.df(seedMaterial, hd.config.Seedlen)
|
||||
copy(hd.state.v, seed)
|
||||
hd.state.c = append(hd.state.c[:0], hd.df(append([]byte{0}, seed...), hd.config.Seedlen)...)
|
||||
hd.state.reseedCounter = 1
|
||||
hd.state.lastReseedTime = time.Now()
|
||||
|
||||
// seed和seedMaterial置0
|
||||
for i := 0; i < len(seed); i++ {
|
||||
seed[i] = 0
|
||||
}
|
||||
for i := 0; i < len(seedMaterial); i++ {
|
||||
seedMaterial[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Generate 输出函数
|
||||
func (hd *HashDrng) Generate(b []byte, additionalInput []byte) error {
|
||||
// hd.mu.Lock()
|
||||
// defer hd.mu.Unlock()
|
||||
|
||||
if len(b) > hd.config.Outlen {
|
||||
return internal.ErrReturnedBitsTooLong
|
||||
}
|
||||
|
||||
// 需要重播种
|
||||
if hd.state.reseedCounter > uint32(hd.config.ReseedIntervalInCounter) ||
|
||||
time.Since(hd.state.lastReseedTime) > hd.config.ReseedIntervalInTime {
|
||||
return internal.ErrNeedReseed
|
||||
}
|
||||
hash := hd.hash.New()
|
||||
if len(additionalInput) > 0 {
|
||||
hash.Write([]byte{2})
|
||||
hash.Write(hd.state.v)
|
||||
hash.Write(additionalInput)
|
||||
W := hash.Sum(nil)
|
||||
internal.AddModBytes(hd.state.v, W)
|
||||
}
|
||||
hash.Reset()
|
||||
_, _ = hash.Write(hd.state.v)
|
||||
temp := hash.Sum(nil)
|
||||
copy(b, temp)
|
||||
hash.Reset()
|
||||
hash.Write([]byte{3})
|
||||
hash.Write(hd.state.v)
|
||||
H := hash.Sum(nil)
|
||||
|
||||
reseedCounterBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(reseedCounterBytes, hd.state.reseedCounter)
|
||||
|
||||
internal.AddModBytes(hd.state.v, H[:])
|
||||
internal.AddModBytes(hd.state.v, hd.state.c)
|
||||
internal.AddModBytes(hd.state.v, reseedCounterBytes)
|
||||
hd.state.reseedCounter++
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package hashrng
|
||||
|
||||
import (
|
||||
_ "crypto/sha256"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/entropy"
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
"xdx.jelly/xgcl/sm"
|
||||
)
|
||||
|
||||
func TestSysEntropySource(t *testing.T) {
|
||||
e := entropy.GetEntropyPool()
|
||||
b, err := e.GetEntropy(128, 128, 128)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Printf("%x\n", b)
|
||||
}
|
||||
|
||||
func TestSm3Df(t *testing.T) {
|
||||
input := make([]byte, 10)
|
||||
for n := 0; n < 100; n++ {
|
||||
output := newDF(sm.SM3)(input, n)
|
||||
if len(output) != n {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0.03GBps, 主要是internal.Outlen太小
|
||||
func TestDrngSpeed(t *testing.T) {
|
||||
raw, _ := NewHashDrng(sm.SM3, Config(internal.SecureLevel2))
|
||||
rng, _ := raw.Instantiate(nil, internal.Nonce(), entropy.GetEntropyPool())
|
||||
msg := make([]byte, rng.OutLen())
|
||||
|
||||
start := time.Now()
|
||||
times := 10000
|
||||
buf := make([]byte, 32)
|
||||
for i := 0; i < times; i++ {
|
||||
if err := rng.Generate(msg, nil); err == internal.ErrNeedReseed {
|
||||
entropy.GetEntropyPool().Read(buf)
|
||||
rng.Reseed(buf, nil)
|
||||
} else if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
end := time.Now()
|
||||
elapsed := end.Sub(start)
|
||||
t.Logf("Generate Random speed: %.2f MBps\n", float64(times*len(msg))/float64(1024*1024)/elapsed.Seconds())
|
||||
}
|
||||
|
||||
// func TestSm3DrngRandomness(t *testing.T) {
|
||||
// // 测试Sm3Drng的随机性测试通过率
|
||||
// total := 10
|
||||
// pass := 0
|
||||
// for i := 0; i < total; i++ {
|
||||
// fmt.Println("======================================", i)
|
||||
// if statistics.SampleSelfTests(Reader) {
|
||||
// fmt.Printf("%d-th test: [O]\n", i)
|
||||
// pass += 1
|
||||
// } else {
|
||||
// fmt.Printf("%d-th test: [X]\n", i)
|
||||
// }
|
||||
// }
|
||||
|
||||
// fmt.Printf("Pass Rate: %d/%d\n", pass, total)
|
||||
// }
|
||||
@@ -0,0 +1,24 @@
|
||||
package hashrng
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
"xdx.jelly/xgcl/sm"
|
||||
)
|
||||
|
||||
// 随机数发生器的已知答案检测
|
||||
func KAT() bool {
|
||||
raw, _ := NewHashDrng(sm.SM3, Config(internal.SecureLevel2))
|
||||
nonce, _ := hex.DecodeString("0001020304050607")
|
||||
entropy, _ := hex.DecodeString("C4F7D581BEFEF25C8BBB6DAD52A6AB8234FA7DB7A988592BC592DAF2BE630647")
|
||||
rng, _ := raw.Instantiate(nil, nonce, bytes.NewReader(entropy))
|
||||
additionalInput, _ := hex.DecodeString("00010203040506")
|
||||
|
||||
rand := make([]byte, 32)
|
||||
rng.Generate(rand, additionalInput)
|
||||
|
||||
wanted, _ := hex.DecodeString("a6e3c0ad539fa0c211b23e3aa7c3b92482bfc77fcb9864690e832bcda4357046")
|
||||
return bytes.Compare(rand, wanted) == 0
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package drng
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/entropy"
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
)
|
||||
|
||||
const ALPHA = 9.5367431640625e-07 // = 2^(-20)
|
||||
|
||||
func next(source entropy.EntropySource) []byte {
|
||||
b, err := source.GetEntropy(internal.MinEntropyInputLength, internal.MinEntropyInputLength, internal.MaxEntropyInputLength)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// 连续健康测试
|
||||
func RepeatCounterHealthyTests(source entropy.EntropySource, n int, H int) bool {
|
||||
C := 1 + int64(math.Ceil(-math.Log2(ALPHA)/float64(H)))
|
||||
A := next(source)
|
||||
if A == nil {
|
||||
return false
|
||||
}
|
||||
B := int64(1)
|
||||
for i := 0; i < n; i++ {
|
||||
X := next(source)
|
||||
if X == nil {
|
||||
return false
|
||||
}
|
||||
if bytes.Equal(X, A) {
|
||||
B++
|
||||
}
|
||||
if B >= C {
|
||||
return false
|
||||
} else {
|
||||
A = X
|
||||
B = 1
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
MinEntropyInputLength = 256 >> 3 // 最小熵阈值256比特
|
||||
MaxEntropyInputLength = (1 << 35) >> 3 // 最大熵阈值2^35比特
|
||||
|
||||
)
|
||||
|
||||
// 可能返回的错误
|
||||
var (
|
||||
ErrNeedReseed = errors.New("[drng] - need reseed")
|
||||
ErrReturnedBitsTooLong = errors.New("[drng] - requested number of bits too long")
|
||||
ErrEntropyLength = errors.New("[drng] - entropy length too short or too long")
|
||||
)
|
||||
|
||||
// 安全级别
|
||||
type SecureLevel uint
|
||||
|
||||
const (
|
||||
SecureLevel1 SecureLevel = 1 + iota
|
||||
SecureLevel2
|
||||
)
|
||||
|
||||
type DrngConfig struct {
|
||||
Seedlen int
|
||||
Outlen int
|
||||
ReseedIntervalInTime time.Duration // 重播种时间阈值
|
||||
ReseedIntervalInCounter int // 重播种计数器阈值
|
||||
MinEntropy int64
|
||||
MinEntropyInputLength int64
|
||||
MaxEntropyInputLength int64
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNonceCounter(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 10000; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
for i := 0; i < 10000; i++ {
|
||||
nonceCounter.LoadAndAdd(1)
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
assert.Equal(t, nonceCounter.n, uint64(10000)*10000)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// RawDrng 未初始化状态,初始化后返回Drng状态
|
||||
// Note: 状态模式
|
||||
type RawDrng interface {
|
||||
// Instantiate 初始化,personalization_string为可选,返回成功则内部状态初始化完成。
|
||||
Instantiate(personalizationString []byte, nonce []byte, entropySource io.Reader) (Drng, error)
|
||||
}
|
||||
|
||||
// Drng is the low level interface for DRNG.
|
||||
//
|
||||
// For most users, use DrngUtil instead.
|
||||
type Drng interface {
|
||||
// Reseed 重播种,entropyInput为输入熵
|
||||
// additionalInput为来自应用的比特串,可以为nil
|
||||
Reseed(entropyInput, additionalInput []byte)
|
||||
|
||||
// Generate 将输出缓冲区b用随机数填充,additionalInputt为来自应用的比特串,可为nil
|
||||
Generate(b []byte, additionalInput []byte) error
|
||||
|
||||
// 每次调用输出的最大字节数(32)
|
||||
OutLen() int
|
||||
|
||||
Config() *DrngConfig
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/internal"
|
||||
)
|
||||
|
||||
// var nonceCounter atomic.Int64
|
||||
|
||||
// atomic.Int64 only available in go 1.19, so we make a new one.
|
||||
type atomicUint64 struct {
|
||||
spin internal.SpinLock
|
||||
n uint64
|
||||
}
|
||||
|
||||
var nonceCounter atomicUint64
|
||||
|
||||
func (a *atomicUint64) LoadAndAdd(n uint64) uint64 {
|
||||
a.spin.Lock()
|
||||
defer a.spin.Unlock()
|
||||
v := a.n
|
||||
a.n += n
|
||||
return v
|
||||
}
|
||||
|
||||
// nonce 由时间戳和单调递增的计数器组成
|
||||
func Nonce() []byte {
|
||||
out := make([]byte, 16)
|
||||
binary.BigEndian.PutUint64(out, uint64(time.Now().UnixNano()))
|
||||
binary.BigEndian.PutUint64(out[8:], nonceCounter.LoadAndAdd(1))
|
||||
return out
|
||||
}
|
||||
|
||||
// AddModBytes a = a+b as integer, a,b are bigendian and len(a) >= len(b).
|
||||
func AddModBytes(a, b []byte) {
|
||||
var x uint
|
||||
|
||||
x = 0
|
||||
i := len(a) - 1
|
||||
j := len(b) - 1
|
||||
for j >= 0 {
|
||||
x += uint(a[i]) + uint(b[j])
|
||||
a[i] = byte(x)
|
||||
x = x >> 8
|
||||
j--
|
||||
i--
|
||||
}
|
||||
if x == 0 {
|
||||
return
|
||||
}
|
||||
for i >= 0 {
|
||||
a[i] += 1
|
||||
if a[i] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func IncBytes(a []byte) {
|
||||
i := len(a) - 1
|
||||
for i >= 0 {
|
||||
a[i]++
|
||||
if a[i] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package grand
|
||||
|
||||
import "xdx.jelly/xgcl/gerrors"
|
||||
|
||||
//go:generate stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go
|
||||
type ErrorCode gerrors.ErrorCode
|
||||
|
||||
func (e ErrorCode) Error() string {
|
||||
return gerrors.Format(uint32(e), e.String())
|
||||
}
|
||||
|
||||
// error codes
|
||||
const (
|
||||
ErrGenerateRandomFailed ErrorCode = gerrors.XDX_JELLY_GCL_GRAND + iota //随机数生成失败
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
// Code generated by "stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go"; DO NOT EDIT.
|
||||
|
||||
package grand
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[ErrGenerateRandomFailed-16850944]
|
||||
}
|
||||
|
||||
const _ErrorCode_name = "随机数生成失败"
|
||||
|
||||
var _ErrorCode_index = [...]uint8{0, 21}
|
||||
|
||||
func (i ErrorCode) String() string {
|
||||
i -= 16850944
|
||||
if i >= ErrorCode(len(_ErrorCode_index)-1) {
|
||||
return "ErrorCode(" + strconv.FormatInt(int64(i+16850944), 10) + ")"
|
||||
}
|
||||
return _ErrorCode_name[_ErrorCode_index[i]:_ErrorCode_index[i+1]]
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
///
|
||||
/// Copyright (c) 2018 xdx. All rights reserved.
|
||||
///
|
||||
/// \file: rand.go
|
||||
///
|
||||
/// \brief: The default random number generators of grand
|
||||
///
|
||||
/// \author: xdx
|
||||
///
|
||||
|
||||
package grand
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
)
|
||||
|
||||
// Reader re-export crypto/rand.Reader. It the default Random number generator of GCL.
|
||||
var Reader = rand.Reader
|
||||
|
||||
// ReaderZero is a Reader which output 000...
|
||||
// Note: only for testing
|
||||
var ReaderZero = ConstantReader(0)
|
||||
|
||||
// ReaderOne is a Reader which output 111...
|
||||
// Note: only for testing
|
||||
var ReaderOne = ConstantReader(1)
|
||||
|
||||
var ReaderTwo = ConstantReader(2)
|
||||
|
||||
// ConstantReader is a reader which outputs constant byte squence.
|
||||
type ConstantReader byte
|
||||
|
||||
// Read implements the io.Reader interface.
|
||||
func (r ConstantReader) Read(b []byte) (int, error) {
|
||||
for i := range b {
|
||||
b[i] = byte(r)
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
// Read is a helper function for grand.Reader.
|
||||
func Read(b []byte) (n int, err error) {
|
||||
return Reader.Read(b)
|
||||
}
|
||||
|
||||
// GenerateRandom is the same as Read.
|
||||
var GenerateRandom = Read
|
||||
|
||||
// GetRandom tries to get a random bytes slice of length.
|
||||
// The return []byte may have a smaller length.
|
||||
func GetRandom(length int) []byte {
|
||||
buf := make([]byte, length)
|
||||
n, _ := Read(buf)
|
||||
return buf[:n]
|
||||
}
|
||||
|
||||
// GenerateRandomExact generates a random slice of length exactly n, or returns error
|
||||
func GenerateRandomExact(n int, r io.Reader) ([]byte, error) {
|
||||
res := make([]byte, n)
|
||||
m, err := r.Read(res)
|
||||
if m < n {
|
||||
return nil, gerrors.WithAnnotating(ErrGenerateRandomFailed, err.Error())
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Int generate a random big.Int of bits bits
|
||||
func Int(bits int) *big.Int {
|
||||
if bits <= 0 {
|
||||
return new(big.Int)
|
||||
}
|
||||
|
||||
// n = 2^bits
|
||||
n := big.NewInt(1)
|
||||
n.Lsh(n, uint(bits))
|
||||
|
||||
m, _ := rand.Int(Reader, n)
|
||||
m.SetBit(m, bits-1, 1)
|
||||
return m
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Deprecated functions //
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// NewReaderFromBytes wraps data to a reader, the return reader could
|
||||
// read at most len(data) bytes.
|
||||
// Note: when return an error, the reader may have read n bytes.
|
||||
//
|
||||
// Deprecated: use bytes.NewReader instead.
|
||||
func NewReaderFromBytes(data []byte) io.Reader {
|
||||
return bytes.NewReader(data)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package grand_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
)
|
||||
|
||||
func TestRandZero(t *testing.T) {
|
||||
randReader := grand.ReaderZero
|
||||
buf := make([]byte, 100)
|
||||
n, err := randReader.Read(buf)
|
||||
if err != nil || n != 100 {
|
||||
t.Log(n, err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandFromBytes(t *testing.T) {
|
||||
buf := make([]byte, 100)
|
||||
_, _ = grand.ReaderOne.Read(buf)
|
||||
fmt.Println(buf)
|
||||
randReader := bytes.NewReader(buf)
|
||||
|
||||
buf2 := make([]byte, 51)
|
||||
n, err := randReader.Read(buf2)
|
||||
fmt.Println(n, err, buf2)
|
||||
if err != nil || n != len(buf2) {
|
||||
t.Log(n, err)
|
||||
t.Fail()
|
||||
}
|
||||
for _, b := range buf2 {
|
||||
if b != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
n, err = randReader.Read(buf2)
|
||||
fmt.Println(n, err, buf2)
|
||||
if err != nil || n != len(buf2) {
|
||||
t.Log(n, err)
|
||||
t.Fail()
|
||||
}
|
||||
for _, b := range buf2 {
|
||||
if b != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestInt(t *testing.T) {
|
||||
for bits := 0; bits < 10000; bits++ {
|
||||
n := grand.Int(bits)
|
||||
if n.BitLen() != bits {
|
||||
t.Fatalf("bits = %d, n = %x", bits, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package grand
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// MustRead tries to fill p with len(p) bytes from r. If it haven't read enough bytes, then an
|
||||
// error returns. So if nil error returns, then p must have read len(p) bytes. Otherwise, only
|
||||
// p[:n] are read from r.
|
||||
func MustRead(r io.Reader, p []byte) (int, error) {
|
||||
n := 0
|
||||
for len(p) > 0 {
|
||||
m, err := r.Read(p)
|
||||
if err != nil {
|
||||
return n + m, err
|
||||
}
|
||||
p = p[m:]
|
||||
n += m
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package elgamal
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
)
|
||||
|
||||
var Reader = grand.Reader
|
||||
|
||||
type Params struct {
|
||||
isMont bool // Is Montgomery represent
|
||||
p *big.Int
|
||||
q *big.Int
|
||||
g *big.Int
|
||||
pMont *big.Int
|
||||
qMont *big.Int
|
||||
gMont *big.Int
|
||||
}
|
||||
|
||||
func (p *Params) P() *big.Int {
|
||||
return p.p
|
||||
}
|
||||
func (p *Params) Q() *big.Int {
|
||||
return p.q
|
||||
}
|
||||
func (p *Params) G() *big.Int {
|
||||
return p.g
|
||||
}
|
||||
|
||||
type PublicKey struct {
|
||||
y big.Int
|
||||
Params *Params
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
x big.Int
|
||||
PublicKey
|
||||
}
|
||||
type Cipher struct {
|
||||
u big.Int
|
||||
v big.Int
|
||||
}
|
||||
|
||||
func GenerateKey(rnd io.Reader, params *Params) (*PrivateKey, *PublicKey, error) {
|
||||
x, err := rand.Int(rnd, params.q)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
y := new(big.Int).Exp(params.g, x, params.p)
|
||||
sk := &PrivateKey{
|
||||
x: *x,
|
||||
PublicKey: PublicKey{
|
||||
y: *y,
|
||||
Params: P1024,
|
||||
},
|
||||
}
|
||||
pk := &sk.PublicKey
|
||||
return sk, pk, nil
|
||||
}
|
||||
|
||||
// m = g^M mod p for some M
|
||||
// rnd can be nil, io.Reader or []byte
|
||||
func (pk *PublicKey) Encryption(m *big.Int, rnd any) (*Cipher, error) {
|
||||
var r *big.Int
|
||||
var err error
|
||||
p := pk.Params.p
|
||||
q := pk.Params.q
|
||||
g := pk.Params.g
|
||||
|
||||
switch rnd := rnd.(type) {
|
||||
case nil:
|
||||
rnd = Reader
|
||||
case io.Reader:
|
||||
r, err = rand.Int(rnd, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case []byte:
|
||||
r = new(big.Int).SetBytes(rnd)
|
||||
if r.Cmp(q) >= 0 {
|
||||
return nil, errors.New("random bytes too large")
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("rnd must be io.Reader or []bytes")
|
||||
}
|
||||
|
||||
c := &Cipher{}
|
||||
c.u.Exp(g, r, p)
|
||||
c.v.Exp(&pk.y, r, p)
|
||||
c.v.Mul(&c.v, m)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (sk *PrivateKey) Decryption(c *Cipher) (*big.Int, error) {
|
||||
p := sk.PublicKey.Params.p
|
||||
u := &c.u
|
||||
v := &c.v
|
||||
z := new(big.Int)
|
||||
z.Exp(u, &sk.x, p)
|
||||
z.ModInverse(z, p)
|
||||
z.Mul(z, v)
|
||||
z.Mod(z, p)
|
||||
return z, nil
|
||||
}
|
||||
|
||||
func (c *Cipher) HomoMap(c1 *Cipher, c2 *Cipher) (*Cipher, error) {
|
||||
c.u.Mul(&c1.u, &c2.u)
|
||||
c.v.Mul(&c1.v, &c2.v)
|
||||
return c, nil
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package elgamal
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
)
|
||||
|
||||
func TestElGamal(t *testing.T) {
|
||||
x := bigFromBase16("013d5955a5e91b8fed1b56b6bdcd467939de9bfc")
|
||||
y := bigFromBase16("b7866990d044b1bccbbcf84c29f145ee17d4f4608c79a55e249e9e108b91e36381944fa3c0c3f51876f63bce7bb30ffde9ca02265e916dd3fb2e060b0dfeaaa67d5a359159b948c3df1141f0e0a22380a3633c1ffbcb1c228ffe4ef0bab52293bfdff4b64e3f362d63b11a4d2507f6e9e98de71aff09fdb64e3737c046044138")
|
||||
// M := bigFromBase16("4142434445464748494a31323334353637383930")
|
||||
// m := new(big.Int).Exp(P1024.g, M, P1024.p)
|
||||
m, _ := rand.Int(grand.Reader, P1024.p)
|
||||
sk := &PrivateKey{
|
||||
x: *x,
|
||||
PublicKey: PublicKey{
|
||||
y: *y,
|
||||
Params: P1024,
|
||||
},
|
||||
}
|
||||
pk := &sk.PublicKey
|
||||
b, _ := hex.DecodeString("d8d0f2d6a3e2d745ab4410e2042a740e7a81a280")
|
||||
c1, err := pk.Encryption(m, b)
|
||||
assert.Nil(t, err)
|
||||
c2, err := pk.Encryption(m, grand.Reader)
|
||||
c, _ := new(Cipher).HomoMap(c1, c2)
|
||||
mm0, _ := sk.Decryption(c)
|
||||
mm1 := new(big.Int).Mul(m, m)
|
||||
mm1.Mod(mm1, pk.Params.p)
|
||||
|
||||
assert.Zero(t, mm0.Cmp(mm1))
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package elgamal
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func bigFromBase16(s string) *big.Int {
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return new(big.Int).SetBytes(b)
|
||||
}
|
||||
|
||||
var P1024 = &Params{
|
||||
p: bigFromBase16("e5256a788f875183ec56a332d38db31de883cded25ae635a656823b5c801b44a104f4e1d604153adaaa5d6d107feb3a8e721a32f3e6780645c85de2d4f4f85568767efc9b8363193497c052a5b832464b81a209d393eb6d3a464cba0b7607dc79b3611dcd1544e4ed329cc913f68234b1d5f209ae7081c0d44662ee1f86c458f"),
|
||||
q: bigFromBase16("e6fa5be8dfd1a200fd699a9ff4b02761f05fca69"),
|
||||
g: bigFromBase16("5a0c1ebde9c0787f3d426e2036455fcd25bc32b1e666b2ba90dad169af7043c18b266d530d0f607ea46c182dd7c88d919158343441e001b10e36c8ffa03cb80dadcf7e84393561d2f4f2d067222d5a33157b81f4f4a46c9526375920cac73c23e100e8b43eb8a4bc83047ae45b079bca6dbf69b4b0c1e6bffdfd232b99c5d61a"),
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
paillier and Elgamal
|
||||
ISO/IEC 18033-6:2019
|
||||
|
||||
TODO: Pailliar with Montgomery multiplication for 2048 bits.
|
||||
@@ -0,0 +1,60 @@
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
|
||||
package paillier
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm4"
|
||||
)
|
||||
|
||||
func TestEnv(t *testing.T) {
|
||||
sk, pk, err := GenerateKey(2048)
|
||||
assert.Nil(t, err)
|
||||
for i := 0; i < 1000; i++ {
|
||||
kek := grand.GetRandom(16) //[]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
|
||||
|
||||
mykey := grand.GetRandom(16)
|
||||
mykeyPaillierCipher, err := EncryptKey(mykey, pk)
|
||||
assert.Nil(t, err)
|
||||
|
||||
iv, mykeyEnvelopeCipher, err := GenEnvelope(mykeyPaillierCipher, kek, pk)
|
||||
assert.Nil(t, err)
|
||||
|
||||
mykeyEnvelope, err := DecryptEnvelope(mykeyEnvelopeCipher, sk) // mykeyEnvelope = SM4CTREnc(kek, mykey) = sm4.Enc(kek, iv) ^ key
|
||||
assert.Nil(t, err)
|
||||
|
||||
// recover mykey from mykeyEnvelope
|
||||
|
||||
mykey2 := DecryptKey(iv []byte, keyEnvelope []byte, pk *PublicKey)
|
||||
|
||||
// check
|
||||
key2, err := sm4.EncryptECB(nil, kek, iv)
|
||||
assert.Nil(t, err)
|
||||
|
||||
for i := range key2 {
|
||||
key2[i] ^= ctrEncKey[i]
|
||||
}
|
||||
assert.Equal(t, key, key2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncKey(t *testing.T) {
|
||||
key := grand.GetRandom(128)
|
||||
|
||||
sk, pk, err := GenerateKey(2048)
|
||||
assert.Nil(t, err)
|
||||
|
||||
c, err := EncryptKey(key, pk)
|
||||
assert.Nil(t, err)
|
||||
|
||||
key2, err := DecryptKey(c, 128, sk)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, key, key2)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package paillier
|
||||
|
||||
// envelope provide hybrid encryption for a user with a remote cryptographic server.
|
||||
// The server has a KEK and the user wants to encrypt a file.
|
||||
// 1. The user generate a random user key ukey
|
||||
// 2. The user use ukey to encrypt the file
|
||||
// 3. The user do the followings to encrypt the ukey with KEK without leaking ukey to the server:
|
||||
// 3-0. The user generate a (temporary or long term) paillier key pair (sk, pk).
|
||||
// 3-1. The user encrypt ukey with paillier encryption: ukeyCipher = PaiEnc(ukey, pk)
|
||||
// 3-2. The server HOMOMORPHICLY encrypt ukey with KEK: ukeyEnvelopeCipher = PaiEnc(SM4Enc(ukey, KEK), pk)
|
||||
// 3-3. The user decrypt ukeyEnvelopeCipher and get ukeyEnvelope = SM4Enc(ukey, KEK)
|
||||
//
|
||||
// The user do the following to decrypt the ukey and then to decrypt the file.
|
||||
// Also without leaking ukey.
|
||||
// 1. The user generate a (temporary or long term) paillier key pair (sk, pk).
|
||||
// 2. User encrypt ukeyEnvelope: ukeyEnvelopeCipher = PaiEnc(ukeyEnvelope, pk)
|
||||
// 3. The server HOMORPHICLY decrypt ukeyEnvelopeCipher: ukeyCipher = PaiEnc(ukey, pk)
|
||||
// 4. The user decrypt ukeyCipher, with ukey.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm4"
|
||||
)
|
||||
|
||||
// xyzw => 0x0y0z0w
|
||||
var tbl = []byte{0, 1, 4, 5, 16, 17, 20, 21, 64, 65, 68, 69, 80, 81, 84, 85}
|
||||
|
||||
type EnvelopeUser struct{}
|
||||
type EnvelopeServer struct{}
|
||||
|
||||
// EncryptUserKey
|
||||
func (EnvelopeUser) EncryptUserKey(ukey []byte, pk *PublicKey) (ukeyCipher *Cipher, err error) {
|
||||
if len(ukey)*8*2 > pk.Bits() {
|
||||
return nil, fmt.Errorf("input key too long, should less than %d bytes", pk.Bits()/8/2)
|
||||
}
|
||||
buf := make([]byte, 0, len(ukey)*2)
|
||||
for _, k := range ukey {
|
||||
buf = append(buf, tbl[k&0xf])
|
||||
buf = append(buf, tbl[k>>4])
|
||||
}
|
||||
return pk.Encrypt(new(big.Int).SetBytes(buf), grand.Reader)
|
||||
}
|
||||
|
||||
func DecryptKey(c *Cipher, keyLength int, priKey *PrivateKey) ([]byte, error) {
|
||||
k, err := priKey.Decrypt(c)
|
||||
_ = err
|
||||
key2 := make([]byte, keyLength*2)
|
||||
k.FillBytes(key2)
|
||||
key := make([]byte, keyLength)
|
||||
for i := 0; i < len(key); i++ {
|
||||
x := key2[2*i]
|
||||
y := key2[2*i+1]
|
||||
n := byte(0)
|
||||
n |= (x >> 0) & 1
|
||||
n |= (x >> 1) & 2
|
||||
n |= (x >> 2) & 4
|
||||
n |= (x >> 3) & 8
|
||||
key[i] = n
|
||||
|
||||
n = byte(0)
|
||||
n |= (y >> 0) & 1
|
||||
n |= (y >> 1) & 2
|
||||
n |= (y >> 2) & 4
|
||||
n |= (y >> 3) & 8
|
||||
key[i] |= (n << 4)
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func GenEnvelope(c0 *Cipher, kek []byte, pubkey *PublicKey) ([]byte, *Cipher, error) {
|
||||
iv := grand.GetRandom(16)
|
||||
c1, err := sm4.EncryptECB(nil, kek, iv) // c1 = sm4.Enc(iv)
|
||||
c2, err := EncryptUserKey(c1, pubkey) // c2 = PaiEnc(sm4.Enc(iv))
|
||||
c2.HomomorphicAdd(c2, c0, pubkey) // c2 = PaiEnc(sm4.Enc(iv) ^ key)
|
||||
|
||||
_ = err
|
||||
return iv, c2, nil
|
||||
}
|
||||
|
||||
func DecryptEnvelope(c *Cipher, prikey *PrivateKey) ([]byte, error) {
|
||||
k, err := prikey.Decrypt(c)
|
||||
_ = err
|
||||
key2 := make([]byte, 32)
|
||||
k.FillBytes(key2)
|
||||
key := make([]byte, 16)
|
||||
for i := 0; i < 16; i++ {
|
||||
x := key2[2*i]
|
||||
y := key2[2*i+1]
|
||||
n := byte(0)
|
||||
n |= (x >> 0) & 1
|
||||
n |= (x >> 1) & 2
|
||||
n |= (x >> 2) & 4
|
||||
n |= (x >> 3) & 8
|
||||
key[i] = n
|
||||
|
||||
n = byte(0)
|
||||
n |= (y >> 0) & 1
|
||||
n |= (y >> 1) & 2
|
||||
n |= (y >> 2) & 4
|
||||
n |= (y >> 3) & 8
|
||||
key[i] |= (n << 4)
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
package paillier
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"sync"
|
||||
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
"golang.org/x/crypto/cryptobyte/asn1"
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/pbkd"
|
||||
)
|
||||
|
||||
//
|
||||
// PublicKey ::= INTEGER
|
||||
//
|
||||
// PrivateKey ::= SEQUENCE{
|
||||
// lambda INTEGER,
|
||||
// N INTEGER
|
||||
// }
|
||||
//
|
||||
// Cipher ::= INTEGER
|
||||
|
||||
type PublicKey struct {
|
||||
N *big.Int
|
||||
N2 *big.Int
|
||||
|
||||
mu sync.Mutex // guard rn
|
||||
rn *big.Int
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
PublicKey
|
||||
lambda *big.Int
|
||||
|
||||
// option
|
||||
lambdaInv *big.Int
|
||||
p, q *big.Int
|
||||
}
|
||||
|
||||
func (k *PrivateKey) Public() *PublicKey {
|
||||
if k.PublicKey.N2 == nil {
|
||||
k.PublicKey.N2 = new(big.Int).Mul(k.PublicKey.N, k.PublicKey.N)
|
||||
}
|
||||
if k.rn == nil {
|
||||
k.Precompute(grand.Reader)
|
||||
}
|
||||
return &k.PublicKey
|
||||
}
|
||||
|
||||
// Cipher the member variable D is for gcl's internal use.
|
||||
// You should never use it except you know what you're doing.
|
||||
type Cipher struct {
|
||||
D *big.Int
|
||||
}
|
||||
|
||||
func newPrivateKey(p *big.Int, q *big.Int) *PrivateKey {
|
||||
sk := &PrivateKey{
|
||||
PublicKey: PublicKey{
|
||||
N: new(big.Int).Mul(p, q),
|
||||
},
|
||||
lambda: new(big.Int),
|
||||
lambdaInv: new(big.Int),
|
||||
}
|
||||
pk := sk.Public()
|
||||
|
||||
// lambda = LCM(p-1, q-1) or just (p-1)*(q-1)
|
||||
// lcm(sk.lambda, new(big.Int).Sub(p, gmath.BigInt1), new(big.Int).Sub(q, gmath.BigInt1))
|
||||
sk.lambda.Mul(new(big.Int).Sub(p, gmath.BigInt1), new(big.Int).Sub(q, gmath.BigInt1))
|
||||
|
||||
sk.lambdaInv.ModInverse(sk.lambda, pk.N)
|
||||
return sk
|
||||
}
|
||||
|
||||
// return l = lcm(a,b)
|
||||
func lcm(l, a, b *big.Int) {
|
||||
d := new(big.Int).GCD(nil, nil, a, b)
|
||||
l.Mul(a, b)
|
||||
l.Div(l, d)
|
||||
}
|
||||
|
||||
// GenerateKey 生成同态密钥. bits 应为2048.
|
||||
// rnd_opt 可选, 忽略则使用grand.Reader.
|
||||
func GenerateKey(bits int, rnd_opt ...io.Reader) (*PrivateKey, *PublicKey, error) {
|
||||
var rnd io.Reader
|
||||
if len(rnd_opt) > 0 {
|
||||
rnd = rnd_opt[0]
|
||||
} else {
|
||||
rnd = grand.Reader
|
||||
}
|
||||
|
||||
priKey := &PrivateKey{}
|
||||
rsaKey, err := rsa.GenerateKey(rnd, bits)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
priKey = newPrivateKey(rsaKey.Primes[0], rsaKey.Primes[1])
|
||||
|
||||
return priKey, &priKey.PublicKey, nil
|
||||
}
|
||||
|
||||
func (k *PrivateKey) Decrypt(c *Cipher) (*big.Int, error) {
|
||||
if c.D == nil || c.D.Cmp(k.N2) >= 0 {
|
||||
return nil, errors.New("invalid cipher")
|
||||
}
|
||||
if k.lambdaInv == nil {
|
||||
k.lambdaInv = new(big.Int).ModInverse(k.lambda, k.N)
|
||||
}
|
||||
pk := k.Public()
|
||||
d := c.D
|
||||
L := new(big.Int)
|
||||
L.Exp(d, k.lambda, pk.N2) // L = c^lambda mod n^2
|
||||
L.Sub(L, gmath.BigInt1)
|
||||
L.Div(L, pk.N) // L = (c^lambda - 1)/n
|
||||
L.Mul(L, k.lambdaInv)
|
||||
L.Mod(L, pk.N)
|
||||
return L, nil
|
||||
}
|
||||
func (k *PublicKey) Bits() int {
|
||||
return k.N.BitLen()
|
||||
}
|
||||
|
||||
// Precompute computes r^N mod N^2 for a random r.
|
||||
func (k *PublicKey) Precompute(rnd io.Reader) error {
|
||||
if k.rn != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
k.mu.Lock()
|
||||
defer k.mu.Unlock()
|
||||
|
||||
if k.N2 == nil {
|
||||
k.N2 = new(big.Int).Mul(k.N, k.N)
|
||||
}
|
||||
|
||||
if k.rn != nil {
|
||||
return nil
|
||||
}
|
||||
buf := make([]byte, k.N.BitLen()/2)
|
||||
_, err := rnd.Read(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf[0] |= 1 // at least one
|
||||
r := new(big.Int).SetBytes(buf)
|
||||
r.Exp(r, k.N, k.N2) // r = r^n mod n^2
|
||||
k.rn = r
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *PublicKey) Encrypt(m *big.Int, rnd io.Reader) (*Cipher, error) {
|
||||
if true {
|
||||
k.Precompute(grand.Reader)
|
||||
rn := new(big.Int).SetBytes(grand.GetRandom(12))
|
||||
rn.Exp(k.rn, rn, k.N2)
|
||||
|
||||
d := new(big.Int)
|
||||
d.Mul(k.N, m) // d = n * m
|
||||
d.Add(d, gmath.BigInt1) // d = nm + 1
|
||||
|
||||
d.Mul(d, rn) // c = (nm+1)*r^n mod n^2
|
||||
d.Mod(d, k.N2)
|
||||
return &Cipher{D: d}, nil
|
||||
} else {
|
||||
// r should select from (1, N)
|
||||
var r *big.Int
|
||||
var err error
|
||||
for {
|
||||
r, err = rand.Int(rnd, k.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// should we check gcd(r,n) == 1?
|
||||
if r.Sign() > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
d := new(big.Int)
|
||||
d.Mul(k.N, m) // d = n * m
|
||||
d.Add(d, gmath.BigInt1) // d = nm + 1
|
||||
|
||||
r.Exp(r, k.N, k.N2) // r = r^n mod n^2
|
||||
// r.SetUint64(1)
|
||||
d.Mul(d, r) // c = (nm+1)*r^n mod n^2
|
||||
d.Mod(d, k.N2)
|
||||
return &Cipher{D: d}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func Encrypt(m *big.Int, publicKey *PublicKey, rnd io.Reader) (*Cipher, error) {
|
||||
return publicKey.Encrypt(m, rnd)
|
||||
}
|
||||
|
||||
func Decrypt(c *Cipher, key *PrivateKey) (*big.Int, error) {
|
||||
return key.Decrypt(c)
|
||||
}
|
||||
|
||||
func GenerateKeyFromPassword(bits int, password []byte, salt []byte, count int) (*PrivateKey, error) {
|
||||
b, err := pbkd.PbkdfWithHmacSm3(password, salt, count, int64((bits+15)/16))
|
||||
pBits := bits / 2
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := big.NewInt(0).SetBytes(b)
|
||||
p.SetBit(p, 0, 1)
|
||||
p.SetBit(p, pBits-1, 1)
|
||||
for !p.ProbablyPrime(20) {
|
||||
p.Add(p, big.NewInt(2))
|
||||
}
|
||||
|
||||
b, err = pbkd.PbkdfWithHmacSm3(password, salt, count+1, int64(bits/16))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q := big.NewInt(0).SetBytes(b)
|
||||
q.SetBit(q, 0, 1)
|
||||
q.SetBit(q, pBits-1, 1)
|
||||
for !q.ProbablyPrime(20) || q.Cmp(p) == 0 {
|
||||
q.Add(q, big.NewInt(2))
|
||||
}
|
||||
return newPrivateKey(p, q), nil
|
||||
}
|
||||
|
||||
func (c *Cipher) Marshal() ([]byte, error) {
|
||||
if c.D == nil {
|
||||
return nil, errors.New("empty cipher")
|
||||
}
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1BigInt(c.D)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (c *Cipher) Unmarshal(b []byte) error {
|
||||
if c.D == nil {
|
||||
c.D = new(big.Int)
|
||||
}
|
||||
input := cryptobyte.String(b)
|
||||
if !input.ReadASN1Integer(c.D) {
|
||||
return errors.New("parse ASN.1 cipher failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// round up n to the nearest power of 2.
|
||||
func roundup(n uint64) uint64 {
|
||||
n--
|
||||
n |= n >> 1
|
||||
n |= n >> 2
|
||||
n |= n >> 4
|
||||
n |= n >> 8
|
||||
n |= n >> 16
|
||||
n |= n >> 32
|
||||
return n + 1
|
||||
}
|
||||
|
||||
func (k *PublicKey) Size() uint {
|
||||
return uint(roundup(uint64(k.N.BitLen())))
|
||||
}
|
||||
|
||||
// Marshal 编码公钥, PublicKey ::= INTEGER
|
||||
func (k *PublicKey) Marshal() ([]byte, error) {
|
||||
if k.N == nil {
|
||||
return nil, errors.New("empty public key")
|
||||
}
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1BigInt(k.N)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (k *PublicKey) Unmarshal(b []byte) error {
|
||||
if k.N == nil || k.N2 == nil {
|
||||
k.N = new(big.Int)
|
||||
k.N2 = new(big.Int)
|
||||
}
|
||||
|
||||
input := cryptobyte.String(b)
|
||||
if !input.ReadASN1Integer(k.N) {
|
||||
return errors.New("parse ASN.1 public key failed")
|
||||
}
|
||||
|
||||
k.N2.Mul(k.N, k.N)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalExt 编码公钥,包括预计算数据, PublicKey ::= INTEGER
|
||||
func (k *PublicKey) MarshalExt() ([]byte, error) {
|
||||
if k.N == nil {
|
||||
return nil, errors.New("empty public key")
|
||||
}
|
||||
k.Precompute(grand.Reader)
|
||||
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
||||
b.AddASN1BigInt(k.N)
|
||||
b.AddASN1BigInt(k.rn)
|
||||
})
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (k *PublicKey) UnmarshalExt(b []byte) error {
|
||||
if k.N == nil || k.N2 == nil {
|
||||
k.N = new(big.Int)
|
||||
k.N2 = new(big.Int)
|
||||
}
|
||||
if k.rn == nil {
|
||||
k.rn = new(big.Int)
|
||||
}
|
||||
|
||||
input := cryptobyte.String(b)
|
||||
var inner cryptobyte.String
|
||||
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
|
||||
!inner.ReadASN1Integer(k.N) ||
|
||||
!inner.ReadASN1Integer(k.rn) {
|
||||
return errors.New("read ASN.1 private key failed")
|
||||
}
|
||||
|
||||
k.N2.Mul(k.N, k.N)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marshal 编码私钥
|
||||
func (k *PrivateKey) Marshal() ([]byte, error) {
|
||||
if k.lambda == nil {
|
||||
return nil, errors.New("empty private key")
|
||||
}
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
||||
b.AddASN1BigInt(k.lambda)
|
||||
b.AddASN1BigInt(k.N)
|
||||
})
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
// Unmarshal 解码私钥
|
||||
func (k *PrivateKey) Unmarshal(b []byte) error {
|
||||
if k.lambda == nil || k.N == nil {
|
||||
k.lambda = new(big.Int)
|
||||
k.N = new(big.Int)
|
||||
}
|
||||
|
||||
input := cryptobyte.String(b)
|
||||
var inner cryptobyte.String
|
||||
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
|
||||
!inner.ReadASN1Integer(k.lambda) ||
|
||||
!inner.ReadASN1Integer(k.N) {
|
||||
return errors.New("read ASN.1 private key failed")
|
||||
}
|
||||
|
||||
if k.lambdaInv == nil {
|
||||
k.lambdaInv = new(big.Int)
|
||||
}
|
||||
k.lambdaInv.ModInverse(k.lambda, k.N)
|
||||
|
||||
_ = k.Public()
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package paillier
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
)
|
||||
|
||||
// HomomorphicAdd set c = Enc(m1+m2) where c1 = Enc(m1) and c2 = Enc(m2)
|
||||
func (c *Cipher) HomomorphicAdd(c1 *Cipher, c2 *Cipher, pk *PublicKey) *Cipher {
|
||||
if c.D == nil {
|
||||
c.D = new(big.Int)
|
||||
}
|
||||
c.D.Mul(c1.D, c2.D)
|
||||
c.D.Mod(c.D, pk.N2)
|
||||
return c
|
||||
}
|
||||
|
||||
// HomomorphicAddInt set c = Enc(m1 + m) where c1 = Enc(m1) and m < N.
|
||||
//
|
||||
// Becareful, if the adversary knows c1, c, and m(or m1), then he can computes m1(or m).
|
||||
// So, using HomomorphicAddInt if you know what you're doing,
|
||||
// otherwise, you should use like this:
|
||||
// c2, err := pk.Encrypt(m, rnd)
|
||||
// c.HomomorphicAdd(c1, c2, pk)
|
||||
func (c *Cipher) HomomorphicAddInt(c1 *Cipher, m *big.Int, pk *PublicKey) *Cipher {
|
||||
d := new(big.Int)
|
||||
c.D = d.Mul(pk.N, m).Add(d, gmath.BigInt1).Mod(d, pk.N2).Mul(d, c1.D).Mod(d, pk.N2)
|
||||
return c
|
||||
}
|
||||
|
||||
// HomomorphicScalarMul if c1 = Enc(a), then HomomorphicScalarMul computes c = Enc(ka)
|
||||
// if ka < n^2.
|
||||
func (c *Cipher) HomomorphicScalarMul(a *Cipher, k *big.Int, pk *PublicKey) *Cipher {
|
||||
if c.D == nil {
|
||||
c.D = new(big.Int)
|
||||
}
|
||||
c.D.Exp(a.D, k, pk.N2)
|
||||
return c
|
||||
}
|
||||
|
||||
// Neg negates the plaintext mod n, i.e., if c = Enc(m), then c.Neg() = Enc(n-m).
|
||||
func (c *Cipher) Neg(pk *PublicKey) *Cipher {
|
||||
c.D.ModInverse(c.D, pk.N2)
|
||||
return c
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package paillier
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
)
|
||||
|
||||
func TestNeg(t *testing.T) {
|
||||
sk, err := GenerateKeyFromPassword(2048, grand.GetRandom(32), grand.GetRandom(32), 1024)
|
||||
assert.Nil(t, err)
|
||||
pk := sk.Public()
|
||||
|
||||
m, _ := rand.Int(grand.Reader, pk.N)
|
||||
mNeg := new(big.Int).Sub(pk.N, m) // n - m
|
||||
c, _ := Encrypt(m, pk, grand.Reader)
|
||||
|
||||
c.Neg(pk) // Enc(n-m) = Enc(m)^-1 mod n^2
|
||||
|
||||
mm, _ := Decrypt(c, sk)
|
||||
|
||||
assert.Zero(t, mm.Cmp(mNeg))
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package paillier
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm2"
|
||||
)
|
||||
|
||||
func bigFromBase16(s string) *big.Int {
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return new(big.Int).SetBytes(b)
|
||||
}
|
||||
|
||||
var p = bigFromBase16("ff03b1a74827c746db83d2eaff00067622f545b62584321256e62b01509f1096" +
|
||||
"2f9c5c8fd0b7f5184a9ce8e81f439df47dda14563dd55a221799d2aa57ed2713" +
|
||||
"271678a5a0b8b40a84ad13d5b6e6599e6467c670109cf1f45ccfed8f75ea3b81" +
|
||||
"4548ab294626fe4d14ff764dd8b091f11a0943a2dd2b983b0df02f4c4d00b413")
|
||||
|
||||
var q = bigFromBase16("dacaabc1dc57faa9fd6a4274c4d588765a1d3311c22e57d8101431b07eb3ddcb" +
|
||||
"05d77d9a742ac2322fe6a063bd1e05acb13b0fe91c70115c2b1eee1155e07252" +
|
||||
"7011a5f849de7072a1ce8e6b71db525fbcda7a89aaed46d27aca5eaeaf35a262" +
|
||||
"70a4a833c5cda681ffd49baa0f610bad100cdf47cc86e5034e2a0b2179e04ec7")
|
||||
|
||||
var n = new(big.Int).Mul(p, q)
|
||||
var lambda = new(big.Int)
|
||||
|
||||
// lcm(lambda, new(big.Int).Sub(p, gmath.BigInt1), new(big.Int).Sub(q, gmath.BigInt1))
|
||||
|
||||
func TestPaillier(t *testing.T) {
|
||||
// pk, sk := GenerateKey(1024)
|
||||
|
||||
sk, err := GenerateKeyFromPassword(2048, grand.GetRandom(32), grand.GetRandom(32), 1024)
|
||||
assert.Nil(t, err)
|
||||
pk := sk.Public()
|
||||
|
||||
m1, _ := rand.Int(grand.Reader, pk.N)
|
||||
m2, _ := rand.Int(grand.Reader, pk.N)
|
||||
c1, _ := Encrypt(m1, pk, grand.Reader)
|
||||
c2, _ := Encrypt(m2, pk, grand.Reader)
|
||||
|
||||
c := new(Cipher).HomomorphicAdd(c1, c2, pk)
|
||||
m, _ := Decrypt(c, sk)
|
||||
|
||||
mm := new(big.Int).Add(m1, m2)
|
||||
mm.Mod(mm, pk.N)
|
||||
assert.Zero(t, m.Cmp(mm))
|
||||
}
|
||||
|
||||
func TestKeyMarshal(t *testing.T) {
|
||||
|
||||
sk, pk, err := GenerateKey(2048, grand.Reader)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, pk.Size(), uint(2048))
|
||||
|
||||
skBytes, err := sk.Marshal()
|
||||
assert.Nil(t, err)
|
||||
sk2 := new(PrivateKey)
|
||||
assert.Nil(t, sk2.Unmarshal(skBytes))
|
||||
assert.Zero(t, sk.p.Cmp(sk2.p)|sk.q.Cmp(sk2.q)|sk.lambda.Cmp(sk2.lambda)|sk.lambdaInv.Cmp(sk2.lambdaInv))
|
||||
|
||||
pkBytes, err := pk.Marshal()
|
||||
assert.Nil(t, err)
|
||||
pk2 := new(PublicKey)
|
||||
assert.Nil(t, pk2.Unmarshal(pkBytes))
|
||||
assert.Zero(t, pk.N.Cmp(pk2.N)|pk.N2.Cmp(pk2.N2))
|
||||
}
|
||||
|
||||
func TestPaillierScalarMul(t *testing.T) {
|
||||
sk, err := GenerateKeyFromPassword(2048, grand.GetRandom(32), grand.GetRandom(32), 1024)
|
||||
assert.Nil(t, err)
|
||||
pk := sk.Public()
|
||||
|
||||
limit := big.NewInt(1)
|
||||
limit.Lsh(limit, 256)
|
||||
ch := time.After(3 * time.Second)
|
||||
done := false
|
||||
for !done {
|
||||
select {
|
||||
case <-ch:
|
||||
done = true
|
||||
default:
|
||||
m, _ := rand.Int(grand.Reader, limit)
|
||||
k, _ := rand.Int(grand.Reader, limit)
|
||||
|
||||
c, _ := Encrypt(m, pk, grand.Reader)
|
||||
c.HomomorphicScalarMul(c, k, sk.Public())
|
||||
|
||||
m1, err := Decrypt(c, sk)
|
||||
assert.Nil(t, err)
|
||||
m2 := new(big.Int).Mul(m, k)
|
||||
assert.Zero(t, m1.Cmp(m2))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParallelPaillierEnc(b *testing.B) {
|
||||
_, pk, _ := GenerateKey(2048, grand.Reader)
|
||||
|
||||
m, _ := rand.Int(grand.Reader, pk.N)
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
Encrypt(m, pk, grand.Reader)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkPaillierEnc(b *testing.B) {
|
||||
_, pk, _ := GenerateKey(2048, grand.Reader)
|
||||
|
||||
m, _ := rand.Int(grand.Reader, pk.N)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Encrypt(m, pk, grand.Reader)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPaillierDec(b *testing.B) {
|
||||
sk, pk, _ := GenerateKey(2048, grand.Reader)
|
||||
|
||||
m, _ := rand.Int(grand.Reader, pk.N)
|
||||
c, _ := Encrypt(m, pk, grand.Reader)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Decrypt(c, sk)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPaillierHomomorphicScalarMul(b *testing.B) {
|
||||
sk, pk, _ := GenerateKey(2048, grand.Reader)
|
||||
|
||||
limit := big.NewInt(1)
|
||||
limit.Lsh(limit, 256)
|
||||
|
||||
m, _ := rand.Int(grand.Reader, limit)
|
||||
c, _ := Encrypt(m, pk, grand.Reader)
|
||||
|
||||
k, _ := rand.Int(grand.Reader, limit)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.HomomorphicScalarMul(c, k, sk.Public())
|
||||
}
|
||||
}
|
||||
func TestPaillierHomomorphicEncSpeed(t *testing.T) {
|
||||
_, pk, _ := GenerateKey(2048, grand.Reader)
|
||||
|
||||
m, _ := rand.Int(grand.Reader, pk.N)
|
||||
|
||||
times := 1000
|
||||
start := time.Now()
|
||||
for i := 0; i < times; i++ {
|
||||
Encrypt(m, pk, grand.Reader)
|
||||
}
|
||||
end := time.Now()
|
||||
elapsed := end.Sub(start)
|
||||
t.Logf("HomomorphicScalarMul: %.2f per second\n", float64(times)/elapsed.Seconds())
|
||||
}
|
||||
|
||||
func TestPaillierHomomorphicScalarMulSpeed(t *testing.T) {
|
||||
_, pk, _ := GenerateKey(2048, grand.Reader)
|
||||
|
||||
limit := big.NewInt(1)
|
||||
limit.Lsh(limit, 256)
|
||||
|
||||
m, _ := rand.Int(grand.Reader, limit)
|
||||
c, _ := Encrypt(m, pk, grand.Reader)
|
||||
|
||||
k, _ := rand.Int(grand.Reader, limit)
|
||||
|
||||
times := 1000
|
||||
start := time.Now()
|
||||
for i := 0; i < times; i++ {
|
||||
c.HomomorphicScalarMul(c, k, pk)
|
||||
}
|
||||
end := time.Now()
|
||||
elapsed := end.Sub(start)
|
||||
t.Logf("HomomorphicScalarMul: %.2f per second\n", float64(times)/elapsed.Seconds())
|
||||
}
|
||||
|
||||
func BenchmarkBlind1(b *testing.B) {
|
||||
_, pk, _ := GenerateKey(2048, grand.Reader)
|
||||
|
||||
limit := big.NewInt(1)
|
||||
limit.Lsh(limit, 256)
|
||||
|
||||
k, _ := rand.Int(grand.Reader, limit)
|
||||
nc, _ := pk.Encrypt(sm2.OrderN(), grand.Reader)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
(&Cipher{}).HomomorphicScalarMul(nc, k, pk)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBlind2(b *testing.B) {
|
||||
_, pk, _ := GenerateKey(2048, grand.Reader)
|
||||
|
||||
limit := big.NewInt(1)
|
||||
limit.Lsh(limit, 256)
|
||||
|
||||
k, _ := rand.Int(grand.Reader, limit)
|
||||
kn := new(big.Int).Mul(k, sm2.OrderN())
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
kn.Mul(k, sm2.OrderN())
|
||||
pk.Encrypt(kn, grand.Reader)
|
||||
}
|
||||
}
|
||||
|
||||
// func BenchmarkGMPIntExp(b *testing.B) {
|
||||
// sk, _, _ := GenerateKey(2048, grand.Reader)
|
||||
// n := gmp.NewInt(1).SetBytes(sk.N.Bytes())
|
||||
// n2 := gmp.NewInt(1).Mul(n, n)
|
||||
|
||||
// r := gmp.NewInt(1).SetBytes(grand.GetRandom(128))
|
||||
// b.ResetTimer()
|
||||
// for i := 0; i < b.N; i++ {
|
||||
// r.Exp(r, n, n2)
|
||||
// }
|
||||
// }
|
||||
|
||||
func BenchmarkIntExp(b *testing.B) {
|
||||
sk, _, _ := GenerateKey(2048, grand.Reader)
|
||||
n := sk.N
|
||||
n2 := sk.N2
|
||||
|
||||
r := new(big.Int).SetBytes(grand.GetRandom(128))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Exp(r, n, n2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateKeyFromPassword(t *testing.T) {
|
||||
b, _ := hex.DecodeString("12345678abcdef")
|
||||
sk, _ := GenerateKeyFromPassword(2048, []byte("1234567812345678"), b, 1024)
|
||||
assert.Equal(t, sk.N.Text(16), "86257d4f684edb672420a6e0d6a6e66b00a316080c0b025d96e9d22c57d6fc7166bcddc07dadc2f0dca7440c6f43a90fab494ea810304af2abc18d54bcdeb8803c8c245270d70b897f3bf2e43c3a5e9d777fb256f84cf5b4705cba19283952dd10aa2b15793a401195ee2a418b999bbf72e35bd94f48267597ab7cfb699b3bbab78a6201a9ee18a22d25e841a66c54d5ebf45c10491ea43cca5e9e6f487c7aedc24d15cda20e6f80a755477b6e2b1d1a9e669ba0773bb31e2fb76e550fdef1be4d02ec820aba5ebfbfd0fbb37bd1c748af1f4a0c17f5cfb41e4cb44a05587bcff2937415eb2e13398da514224def6c03f61a07319512362912caa08bded076dd")
|
||||
assert.Equal(t, sk.Size(), uint(2048))
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user