-
Notifications
You must be signed in to change notification settings - Fork 0
/
ecies.go
99 lines (77 loc) · 1.9 KB
/
ecies.go
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package ecies
import (
"crypto/rand"
"crypto/sha512"
"fmt"
"io"
"golang.org/x/crypto/curve25519"
)
// NewCurve25519ECDH 使用密码学家Daniel J. Bernstein的椭圆曲线算法:Curve25519来创建ECDH实例
// 因为Curve25519独立于NIST之外, 没在标准库实现, 需要单独为期实现一套接口来支持
// GenerateKey 基于curve25519椭圆曲线算法生成秘钥对(32位)
func GenerateKey() (priv, pub [32]byte, err error) {
_, err = io.ReadFull(rand.Reader, priv[:])
if err != nil {
return
}
priv[0] &= 248
priv[31] &= 127
priv[31] |= 64
curve25519.ScalarBaseMult(&pub, &priv)
return priv, pub, nil
}
// Encrypt 加密
func Encrypt(plainText []byte, publicKey [32]byte) ([]byte, error) {
var (
r, R, S, kb [32]byte
)
if _, err := rand.Read(r[:]); err != nil {
return nil, err
}
r[0] &= 248
r[31] &= 127
r[31] |= 64
kb = publicKey
curve25519.ScalarBaseMult(&R, &r)
curve25519.ScalarMult(&S, &r, &kb)
ke := make([]byte, 0, len(plainText))
for {
if len(ke) > len(plainText) {
break
}
for _, b := range sha512.Sum512(S[:]) {
ke = append(ke, b)
}
}
cipherText := make([]byte, 32+len(plainText))
copy(cipherText[:32], R[:])
for i := 0; i < len(plainText); i++ {
cipherText[32+i] = plainText[i] ^ ke[i]
}
return cipherText, nil
}
// Decrypt 解密
func Decrypt(cipherText []byte, privateKey [32]byte) ([]byte, error) {
if len(cipherText) <= 32 {
return nil, fmt.Errorf("not an validate cipher data, must > 32byte")
}
var R, S, kb [32]byte
copy(R[:], cipherText[:32])
kb = privateKey
curve25519.ScalarMult(&S, &kb, &R)
plainText := make([]byte, len(cipherText)-32)
ke := make([]byte, 0, len(plainText))
for {
if len(ke) < len(plainText) {
for _, b := range sha512.Sum512(S[:]) {
ke = append(ke, b)
}
} else {
break
}
}
for i := 0; i < len(plainText); i++ {
plainText[i] = cipherText[32+i] ^ ke[i]
}
return plainText, nil
}