mirror of
https://github.com/wumansgy/goEncrypt.git
synced 2025-10-23 15:43:11 +08:00
GO加密函数封装
This commit is contained in:
83
.idea/workspace.xml
generated
83
.idea/workspace.xml
generated
@@ -2,10 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="879b126a-5488-4e29-a4e1-3a8936e89a2d" name="默认的" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/AES_CBC.go" beforeDir="false" afterPath="$PROJECT_DIR$/AES_CBC.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/DES_CBC.go" beforeDir="false" afterPath="$PROJECT_DIR$/DES_CBC.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/RsaCrypt.go" beforeDir="false" afterPath="$PROJECT_DIR$/RsaCrypt.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/GetECCKey.go" beforeDir="false" afterPath="$PROJECT_DIR$/GetECCKey.go" afterDir="false" />
|
||||
</list>
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="TRACKING_ENABLED" value="true" />
|
||||
@@ -15,12 +12,24 @@
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileEditorManager">
|
||||
<leaf>
|
||||
<file leaf-file-name="EccSign.go" pinned="false" current-in-tab="true">
|
||||
<entry file="file://$PROJECT_DIR$/EccSign.go">
|
||||
<leaf SIDE_TABS_SIZE_LIMIT_KEY="375">
|
||||
<file leaf-file-name="ecies.go" pinned="false" current-in-tab="true">
|
||||
<entry file="file://$PROJECT_DIR$/ecies.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="837">
|
||||
<caret line="82" lean-forward="true" selection-start-line="82" selection-end-line="82" />
|
||||
<state relative-caret-position="7506">
|
||||
<caret line="391" column="5" selection-start-line="391" selection-start-column="5" selection-end-line="391" selection-end-column="5" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="EccCrypt.go" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/EccCrypt.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-891">
|
||||
<caret line="39" column="35" selection-start-line="39" selection-start-column="35" selection-end-line="39" selection-end-column="35" />
|
||||
<folding>
|
||||
<element signature="e#15#153#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
@@ -40,6 +49,8 @@
|
||||
<option value="$PROJECT_DIR$/DES_CBC.go" />
|
||||
<option value="$PROJECT_DIR$/GetECCKey.go" />
|
||||
<option value="$PROJECT_DIR$/EccSign.go" />
|
||||
<option value="$PROJECT_DIR$/ecies.go" />
|
||||
<option value="$PROJECT_DIR$/EccCrypt.go" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
@@ -66,7 +77,6 @@
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="Scope" />
|
||||
<pane id="ProjectPane">
|
||||
<subPane>
|
||||
<expand>
|
||||
@@ -78,6 +88,7 @@
|
||||
<select />
|
||||
</subPane>
|
||||
</pane>
|
||||
<pane id="Scope" />
|
||||
</panes>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
@@ -103,7 +114,7 @@
|
||||
<frame x="-8" y="-8" width="1456" height="886" extended-state="6" />
|
||||
<editor active="true" />
|
||||
<layout>
|
||||
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.21748555" />
|
||||
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.22182082" />
|
||||
<window_info anchor="bottom" id="TODO" order="6" />
|
||||
<window_info anchor="bottom" id="调试" order="7" />
|
||||
<window_info anchor="bottom" id="Event Log" order="7" side_tool="true" />
|
||||
@@ -111,8 +122,8 @@
|
||||
<window_info anchor="bottom" id="Database Changes" order="7" show_stripe_button="false" />
|
||||
<window_info anchor="bottom" id="Version Control" order="7" show_stripe_button="false" />
|
||||
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
|
||||
<window_info anchor="bottom" id="Terminal" order="7" />
|
||||
<window_info anchor="bottom" id="运行" order="7" />
|
||||
<window_info anchor="bottom" id="Terminal" order="7" />
|
||||
<window_info id="Favorites" order="2" side_tool="true" />
|
||||
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
||||
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
||||
@@ -132,6 +143,13 @@
|
||||
<option name="myLimit" value="2678400000" />
|
||||
</component>
|
||||
<component name="editorHistoryManager">
|
||||
<entry file="file://$PROJECT_DIR$/EccSign.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1971">
|
||||
<caret line="82" lean-forward="true" selection-start-line="82" selection-end-line="82" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/GetRsakey.go">
|
||||
<provider selected="true" editor-type-id="text-editor" />
|
||||
</entry>
|
||||
@@ -160,16 +178,6 @@
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/AES_CBC.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1807">
|
||||
<caret line="83" column="9" lean-forward="true" selection-start-line="83" selection-start-column="9" selection-end-line="83" selection-end-column="9" />
|
||||
<folding>
|
||||
<element signature="e#19#87#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/RsaCrypt.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-162">
|
||||
@@ -199,8 +207,35 @@
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/EccSign.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="837">
|
||||
<caret line="82" lean-forward="true" selection-start-line="82" selection-end-line="82" />
|
||||
<state relative-caret-position="1566">
|
||||
<caret line="67" column="18" selection-start-line="67" selection-start-column="18" selection-end-line="67" selection-end-column="18" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/AES_CBC.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="592">
|
||||
<caret line="83" column="9" lean-forward="true" selection-start-line="83" selection-start-column="9" selection-end-line="83" selection-end-column="9" />
|
||||
<folding>
|
||||
<element signature="e#19#87#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/EccCrypt.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-891">
|
||||
<caret line="39" column="35" selection-start-line="39" selection-start-column="35" selection-end-line="39" selection-end-column="35" />
|
||||
<folding>
|
||||
<element signature="e#15#153#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/ecies.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="7506">
|
||||
<caret line="391" column="5" selection-start-line="391" selection-start-column="5" selection-end-line="391" selection-end-column="5" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
|
92
EccCrypt.go
Normal file
92
EccCrypt.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package wmgocrypt
|
||||
|
||||
import (
|
||||
"log"
|
||||
"crypto/rand"
|
||||
"encoding/pem"
|
||||
"runtime"
|
||||
"crypto/x509"
|
||||
"crypto/ecdsa"
|
||||
)
|
||||
|
||||
/*
|
||||
@Time : 2018/11/4 16:43
|
||||
@Author : wuman
|
||||
@File : EccCrypt
|
||||
@Software: GoLand
|
||||
*/
|
||||
func init(){
|
||||
log.SetFlags(log.Ldate|log.Lshortfile)
|
||||
} //处理日志的格式
|
||||
//Ecc椭圆曲线的公钥加密,如果要解密对应着私钥解密
|
||||
/*func EccEnCrypt(plainText []byte,prv2 *ecies.PrivateKey)(crypText []byte,err error){
|
||||
|
||||
ct, err := ecies.Encrypt(rand.Reader, &prv2.PublicKey, plainText, nil, nil)
|
||||
return ct, err
|
||||
}
|
||||
//直接解密
|
||||
func EccDeCrypt(cryptText []byte,prv2 *ecies.PrivateKey) ([]byte, error) {
|
||||
pt, err := prv2.Decrypt(cryptText, nil, nil)
|
||||
return pt, err
|
||||
}*/
|
||||
|
||||
//传入公钥和明文用来加密
|
||||
func EccPublicEncrypt(plainText []byte,key []byte)( cryptText []byte,err error){ //用私钥解密
|
||||
//1. pem 解码
|
||||
block, _:= pem.Decode(key)
|
||||
|
||||
//防止用户传的密钥不正确导致panic,这里恢复程序并打印错误
|
||||
defer func(){
|
||||
if err:=recover();err!=nil{
|
||||
switch err.(type){
|
||||
case runtime.Error:
|
||||
log.Println("runtime err:",err,"请检查密钥是否正确")
|
||||
default:
|
||||
log.Println("error:",err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
//2. block中的Bytes是x509编码的内容, x509解码
|
||||
tempPublicKey, _ := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
//解码得到ecdsa包中的私钥
|
||||
//类型断言
|
||||
publicKey1:=tempPublicKey.(*ecdsa.PublicKey)
|
||||
//转换为以太坊包中的ecies包中的私钥
|
||||
publicKey:=ImportECDSAPublic(publicKey1)
|
||||
//用私钥来解密密文
|
||||
crypttext,err:=Encrypt(rand.Reader, publicKey, plainText, nil, nil)
|
||||
|
||||
return crypttext,err
|
||||
|
||||
|
||||
}
|
||||
|
||||
//传入私钥和明文用来解密
|
||||
func EccPrivateDeCrypt(cryptText []byte,key []byte)( msg []byte,err error){ //用私钥解密
|
||||
//1. pem 解码
|
||||
block, _:= pem.Decode(key)
|
||||
|
||||
//防止用户传的密钥不正确导致panic,这里恢复程序并打印错误
|
||||
defer func(){
|
||||
if err:=recover();err!=nil{
|
||||
switch err.(type){
|
||||
case runtime.Error:
|
||||
log.Println("runtime err:",err,"请检查密钥是否正确")
|
||||
default:
|
||||
log.Println("error:",err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
//2. block中的Bytes是x509编码的内容, x509解码
|
||||
tempPrivateKey, _ := x509.ParseECPrivateKey(block.Bytes)
|
||||
//解码得到ecdsa包中的私钥
|
||||
//转换为以太坊包中的ecies包中的私钥
|
||||
privateKey:=ImportECDSA(tempPrivateKey)
|
||||
|
||||
//用私钥来解密密文
|
||||
plainText,err:=privateKey.Decrypt(cryptText,nil,nil)
|
||||
|
||||
return plainText,err
|
||||
|
||||
|
||||
}
|
@@ -22,7 +22,7 @@ func init(){
|
||||
//ECC椭圆曲线密钥对生成
|
||||
func GetEccKey(){
|
||||
//1.生成密钥对
|
||||
privateKey, _ := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||
privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
|
||||
//2.将密钥保存到相关的文件中
|
||||
// x509标准编码
|
||||
|
46
README.md
46
README.md
@@ -297,6 +297,52 @@ W/fnOWXyXQ7DB16jMSQ=
|
||||
|
||||
> ECC椭圆曲线技术应用广泛,目前我国居民身份证数字签名技术就是使用的ECC,虚拟货币比特币和以太坊中也使用了ECC技术,后面我们会把ECC加密的方法也实现好。
|
||||
|
||||
#### 4.3 ECC用作加密十用(非对称加密是用公钥来加密,私钥来解密的,由于GO标准包中没有实现ECC加密的接口,只实现了ECC数字签名的接口,我们找了以太坊源码中的ECC加密的使用方法,稍加改造了一下,拿过来用了,在这里调用了以太坊加密包里面的接口来实现ECC加密的方法,我们把加密的东西二次封装了一下,下载包后就可以直接使用)
|
||||
|
||||
首先还是先得到公钥和私钥
|
||||
|
||||
```
|
||||
func main(){
|
||||
wmgocrypt.GetEccKey()
|
||||
} //这里我们得到的密钥是通过P256曲线得到的,由于之前验证用别的曲线调用以太坊接口会报错
|
||||
```
|
||||
|
||||
然后就可以快速使用了
|
||||
|
||||
```
|
||||
func main(){
|
||||
plainText:=[]byte("窗前明月光,疑是地上霜,ECC加密解密")
|
||||
|
||||
//这里传入的私钥和公钥是要用GetECCKey里面得到的私钥和公钥,如果自己封装的话,
|
||||
// 获取密钥时传入的第一个参数是要用这条曲线elliptic.P256(),如果用别的会报无效公钥错误,
|
||||
// 例如用P521()这条曲线
|
||||
privateKey:=[]byte(`-----BEGIN WUMAN ECC PRIVATE KEY-----
|
||||
MHcCAQEEIKozbXD9G6bGPJ26cCAfEdLrqAe697F8SiLRMdqxzNQ5oAoGCCqGSM49
|
||||
AwEHoUQDQgAEk3/hltyR0r0J2Wkkhi4HaREJXS1vFooGpsKCbLvrdUW4peVIwKEW
|
||||
+yC3/g2X7Q2A8ftJlYv2X4kDU180GhIQpA==
|
||||
-----END WUMAN ECC PRIVATE KEY-----
|
||||
`)
|
||||
publicKey:=[]byte(`-----BEGIN WUMAN ECC PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEk3/hltyR0r0J2Wkkhi4HaREJXS1v
|
||||
FooGpsKCbLvrdUW4peVIwKEW+yC3/g2X7Q2A8ftJlYv2X4kDU180GhIQpA==
|
||||
-----END WUMAN ECC PUBLIC KEY-----
|
||||
`)
|
||||
|
||||
cryptText,_:=wmgocrypt.EccPublicEncrypt(plainText,publicKey)
|
||||
fmt.Println("ECC传入公钥加密的密文为:",hex.EncodeToString(cryptText))
|
||||
|
||||
msg,err:=wmgocrypt.EccPrivateDeCrypt(cryptText,privateKey)
|
||||
if err!=nil{
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println("ECC传入私钥解密后的明文为:",string(msg))
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 5.附带的哈希函数sha256和sha512使用非常简单
|
||||
|
||||
#### 5.1 sh256的快速使用
|
||||
|
424
ecies.go
Normal file
424
ecies.go
Normal file
@@ -0,0 +1,424 @@
|
||||
// Copyright (c) 2013 Kyle Isom <kyle@tyrfingr.is>
|
||||
// Copyright (c) 2012 The Go Authors. 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.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// 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
|
||||
// OWNER 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.
|
||||
|
||||
package wmgocrypt
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/hmac"
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"math/big"
|
||||
"crypto"
|
||||
"crypto/sha256"
|
||||
"crypto/aes"
|
||||
"crypto/sha512"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrImport = fmt.Errorf("ecies: failed to import key")
|
||||
ErrInvalidCurve = fmt.Errorf("ecies: invalid elliptic curve")
|
||||
ErrInvalidParams = fmt.Errorf("ecies: invalid ECIES parameters")
|
||||
ErrInvalidPublicKey = fmt.Errorf("ecies: invalid public key")
|
||||
ErrSharedKeyIsPointAtInfinity = fmt.Errorf("ecies: shared key is point at infinity")
|
||||
ErrSharedKeyTooBig = fmt.Errorf("ecies: shared key params are too big")
|
||||
ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters")
|
||||
|
||||
)
|
||||
|
||||
// PublicKey is a representation of an elliptic curve public key.
|
||||
type PublicKey struct {
|
||||
X *big.Int
|
||||
Y *big.Int
|
||||
elliptic.Curve
|
||||
Params *ECIESParams
|
||||
}
|
||||
|
||||
// Export an ECIES public key as an ECDSA public key.
|
||||
func (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey {
|
||||
return &ecdsa.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y}
|
||||
}
|
||||
|
||||
// Import an ECDSA public key as an ECIES public key.
|
||||
func ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey {
|
||||
return &PublicKey{
|
||||
X: pub.X,
|
||||
Y: pub.Y,
|
||||
Curve: pub.Curve,
|
||||
Params: ParamsFromCurve(pub.Curve),
|
||||
}
|
||||
}
|
||||
|
||||
// PrivateKey is a representation of an elliptic curve private key.
|
||||
type PrivateKey struct {
|
||||
PublicKey
|
||||
D *big.Int
|
||||
}
|
||||
|
||||
// Export an ECIES private key as an ECDSA private key.
|
||||
func (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey {
|
||||
pub := &prv.PublicKey
|
||||
pubECDSA := pub.ExportECDSA()
|
||||
return &ecdsa.PrivateKey{PublicKey: *pubECDSA, D: prv.D}
|
||||
}
|
||||
|
||||
// Import an ECDSA private key as an ECIES private key.
|
||||
func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey {
|
||||
pub := ImportECDSAPublic(&prv.PublicKey)
|
||||
return &PrivateKey{*pub, prv.D}
|
||||
}
|
||||
|
||||
// Generate an elliptic curve public / private keypair. If params is nil,
|
||||
// the recommended default parameters for the key will be chosen.
|
||||
func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) {
|
||||
pb, x, y, err := elliptic.GenerateKey(curve, rand)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
prv = new(PrivateKey)
|
||||
prv.PublicKey.X = x
|
||||
prv.PublicKey.Y = y
|
||||
prv.PublicKey.Curve = curve
|
||||
prv.D = new(big.Int).SetBytes(pb)
|
||||
if params == nil {
|
||||
params = ParamsFromCurve(curve)
|
||||
}
|
||||
prv.PublicKey.Params = params
|
||||
return
|
||||
}
|
||||
|
||||
// MaxSharedKeyLength returns the maximum length of the shared key the
|
||||
// public key can produce.
|
||||
func MaxSharedKeyLength(pub *PublicKey) int {
|
||||
return (pub.Curve.Params().BitSize + 7) / 8
|
||||
}
|
||||
|
||||
// ECDH key agreement method used to establish secret keys for encryption.
|
||||
func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) {
|
||||
if prv.PublicKey.Curve != pub.Curve {
|
||||
return nil, ErrInvalidCurve
|
||||
}
|
||||
if skLen+macLen > MaxSharedKeyLength(pub) {
|
||||
return nil, ErrSharedKeyTooBig
|
||||
}
|
||||
|
||||
x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes())
|
||||
if x == nil {
|
||||
return nil, ErrSharedKeyIsPointAtInfinity
|
||||
}
|
||||
|
||||
sk = make([]byte, skLen+macLen)
|
||||
skBytes := x.Bytes()
|
||||
copy(sk[len(sk)-len(skBytes):], skBytes)
|
||||
return sk, nil
|
||||
}
|
||||
|
||||
var (
|
||||
ErrKeyDataTooLong = fmt.Errorf("ecies: can't supply requested key data")
|
||||
ErrSharedTooLong = fmt.Errorf("ecies: shared secret is too long")
|
||||
ErrInvalidMessage = fmt.Errorf("ecies: invalid message")
|
||||
)
|
||||
|
||||
var (
|
||||
big2To32 = new(big.Int).Exp(big.NewInt(2), big.NewInt(32), nil)
|
||||
big2To32M1 = new(big.Int).Sub(big2To32, big.NewInt(1))
|
||||
)
|
||||
|
||||
func incCounter(ctr []byte) {
|
||||
if ctr[3]++; ctr[3] != 0 {
|
||||
return
|
||||
}
|
||||
if ctr[2]++; ctr[2] != 0 {
|
||||
return
|
||||
}
|
||||
if ctr[1]++; ctr[1] != 0 {
|
||||
return
|
||||
}
|
||||
if ctr[0]++; ctr[0] != 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1).
|
||||
func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) (k []byte, err error) {
|
||||
if s1 == nil {
|
||||
s1 = make([]byte, 0)
|
||||
}
|
||||
|
||||
reps := ((kdLen + 7) * 8) / (hash.BlockSize() * 8)
|
||||
if big.NewInt(int64(reps)).Cmp(big2To32M1) > 0 {
|
||||
fmt.Println(big2To32M1)
|
||||
return nil, ErrKeyDataTooLong
|
||||
}
|
||||
|
||||
counter := []byte{0, 0, 0, 1}
|
||||
k = make([]byte, 0)
|
||||
|
||||
for i := 0; i <= reps; i++ {
|
||||
hash.Write(counter)
|
||||
hash.Write(z)
|
||||
hash.Write(s1)
|
||||
k = append(k, hash.Sum(nil)...)
|
||||
hash.Reset()
|
||||
incCounter(counter)
|
||||
}
|
||||
|
||||
k = k[:kdLen]
|
||||
return
|
||||
}
|
||||
|
||||
// messageTag computes the MAC of a message (called the tag) as per
|
||||
// SEC 1, 3.5.
|
||||
func messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte {
|
||||
mac := hmac.New(hash, km)
|
||||
mac.Write(msg)
|
||||
mac.Write(shared)
|
||||
tag := mac.Sum(nil)
|
||||
return tag
|
||||
}
|
||||
|
||||
// Generate an initialisation vector for CTR mode.
|
||||
func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) {
|
||||
iv = make([]byte, params.BlockSize)
|
||||
_, err = io.ReadFull(rand, iv)
|
||||
return
|
||||
}
|
||||
|
||||
// symEncrypt carries out CTR encryption using the block cipher specified in the
|
||||
// parameters.
|
||||
func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) {
|
||||
c, err := params.Cipher(key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
iv, err := generateIV(params, rand)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ctr := cipher.NewCTR(c, iv)
|
||||
|
||||
ct = make([]byte, len(m)+params.BlockSize)
|
||||
copy(ct, iv)
|
||||
ctr.XORKeyStream(ct[params.BlockSize:], m)
|
||||
return
|
||||
}
|
||||
|
||||
// symDecrypt carries out CTR decryption using the block cipher specified in
|
||||
// the parameters
|
||||
func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) {
|
||||
c, err := params.Cipher(key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ctr := cipher.NewCTR(c, ct[:params.BlockSize])
|
||||
|
||||
m = make([]byte, len(ct)-params.BlockSize)
|
||||
ctr.XORKeyStream(m, ct[params.BlockSize:])
|
||||
return
|
||||
}
|
||||
|
||||
// Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1.
|
||||
//
|
||||
// s1 and s2 contain shared information that is not part of the resulting
|
||||
// ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the
|
||||
// shared information parameters aren't being used, they should be nil.
|
||||
func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) {
|
||||
params := pub.Params
|
||||
if params == nil {
|
||||
if params = ParamsFromCurve(pub.Curve); params == nil {
|
||||
err = ErrUnsupportedECIESParameters
|
||||
return
|
||||
}
|
||||
}
|
||||
R, err := GenerateKey(rand, pub.Curve, params)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hash := params.Hash()
|
||||
z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
Ke := K[:params.KeyLen]
|
||||
Km := K[params.KeyLen:]
|
||||
hash.Write(Km)
|
||||
Km = hash.Sum(nil)
|
||||
hash.Reset()
|
||||
|
||||
em, err := symEncrypt(rand, params, Ke, m)
|
||||
if err != nil || len(em) <= params.BlockSize {
|
||||
return
|
||||
}
|
||||
|
||||
d := messageTag(params.Hash, Km, em, s2)
|
||||
|
||||
Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y)
|
||||
ct = make([]byte, len(Rb)+len(em)+len(d))
|
||||
copy(ct, Rb)
|
||||
copy(ct[len(Rb):], em)
|
||||
copy(ct[len(Rb)+len(em):], d)
|
||||
return
|
||||
}
|
||||
|
||||
// Decrypt decrypts an ECIES ciphertext.
|
||||
func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
|
||||
if len(c) == 0 {
|
||||
return nil, ErrInvalidMessage
|
||||
}
|
||||
params := prv.PublicKey.Params
|
||||
if params == nil {
|
||||
if params = ParamsFromCurve(prv.PublicKey.Curve); params == nil {
|
||||
err = ErrUnsupportedECIESParameters
|
||||
return
|
||||
}
|
||||
}
|
||||
hash := params.Hash()
|
||||
|
||||
var (
|
||||
rLen int
|
||||
hLen int = hash.Size()
|
||||
mStart int
|
||||
mEnd int
|
||||
)
|
||||
|
||||
switch c[0] {
|
||||
case 2, 3, 4:
|
||||
rLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4
|
||||
if len(c) < (rLen + hLen + 1) {
|
||||
err = ErrInvalidMessage
|
||||
return
|
||||
}
|
||||
default:
|
||||
err = ErrInvalidPublicKey
|
||||
return
|
||||
}
|
||||
|
||||
mStart = rLen
|
||||
mEnd = len(c) - hLen
|
||||
|
||||
R := new(PublicKey)
|
||||
R.Curve = prv.PublicKey.Curve
|
||||
R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen])
|
||||
if R.X == nil {
|
||||
err = ErrInvalidPublicKey
|
||||
return
|
||||
}
|
||||
if !R.Curve.IsOnCurve(R.X, R.Y) {
|
||||
err = ErrInvalidCurve
|
||||
return
|
||||
}
|
||||
|
||||
z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
Ke := K[:params.KeyLen]
|
||||
Km := K[params.KeyLen:]
|
||||
hash.Write(Km)
|
||||
Km = hash.Sum(nil)
|
||||
hash.Reset()
|
||||
|
||||
d := messageTag(params.Hash, Km, c[mStart:mEnd], s2)
|
||||
if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 {
|
||||
err = ErrInvalidMessage
|
||||
return
|
||||
}
|
||||
|
||||
m, err = symDecrypt(params, Ke, c[mStart:mEnd])
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
//以下为从以太坊源码/crypt/ecies/params.go中截取过来
|
||||
func ParamsFromCurve(curve elliptic.Curve) (params *ECIESParams) {
|
||||
return paramsFromCurve[curve]
|
||||
}
|
||||
var paramsFromCurve = map[elliptic.Curve]*ECIESParams{
|
||||
//ethcrypto.S256(): ECIES_AES128_SHA256,
|
||||
elliptic.P256(): ECIES_AES128_SHA256,
|
||||
elliptic.P384(): ECIES_AES256_SHA384,
|
||||
elliptic.P521(): ECIES_AES256_SHA512,
|
||||
}
|
||||
var (
|
||||
ECIES_AES128_SHA256 = &ECIESParams{
|
||||
Hash: sha256.New,
|
||||
hashAlgo: crypto.SHA256,
|
||||
Cipher: aes.NewCipher,
|
||||
BlockSize: aes.BlockSize,
|
||||
KeyLen: 16,
|
||||
}
|
||||
|
||||
ECIES_AES256_SHA256 = &ECIESParams{
|
||||
Hash: sha256.New,
|
||||
hashAlgo: crypto.SHA256,
|
||||
Cipher: aes.NewCipher,
|
||||
BlockSize: aes.BlockSize,
|
||||
KeyLen: 32,
|
||||
}
|
||||
|
||||
ECIES_AES256_SHA384 = &ECIESParams{
|
||||
Hash: sha512.New384,
|
||||
hashAlgo: crypto.SHA384,
|
||||
Cipher: aes.NewCipher,
|
||||
BlockSize: aes.BlockSize,
|
||||
KeyLen: 32,
|
||||
}
|
||||
|
||||
ECIES_AES256_SHA512 = &ECIESParams{
|
||||
Hash: sha512.New,
|
||||
hashAlgo: crypto.SHA512,
|
||||
Cipher: aes.NewCipher,
|
||||
BlockSize: aes.BlockSize,
|
||||
KeyLen: 32,
|
||||
}
|
||||
)
|
||||
type ECIESParams struct {
|
||||
Hash func() hash.Hash // hash function
|
||||
hashAlgo crypto.Hash
|
||||
Cipher func([]byte) (cipher.Block, error) // symmetric cipher
|
||||
BlockSize int // block size of symmetric cipher
|
||||
KeyLen int // length of symmetric key
|
||||
}
|
BIN
image/16.png
Normal file
BIN
image/16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Reference in New Issue
Block a user