CTR 全称为计数器模式(Counter mode),该模式由 Diffe 和 Hellman 设计。一种分组密码的模式
一种密钥交换协议,注意该算法只能用于密钥的交换,而不能进行消息的加密和解密。双方确定要用的密钥后,要使用其他对称密钥操作加密算法实际加密和解密消息。它可以让双方在不泄漏密钥的情况下协商出一个密钥来, 常用于保证对称加密的秘钥的安全, TLS就是这样做的。
引用git: dh go实现
// Use of this source code is governed by a license
// that can be found in the LICENSE file.
// Package dh implements the Diffie-Hellman key exchange over
// multiplicative groups of integers modulo a prime.
// This also defines some commen groups described in RFC 3526.
package dh
import (
cryptorand "crypto/rand"
"errors"
"io"
"math/big"
)
var zero *big.Int = big.NewInt(0)
var one *big.Int = big.NewInt(1)
var two *big.Int = big.NewInt(2)
// IsSafePrime returns true, if the prime of the group is
// a so called safe-prime. For a group with a safe-prime prime
// number the Decisional-Diffie-Hellman-Problem (DDH) is a
// 'hard' problem. The n argument is the number of iterations
// for the probabilistic prime test.
// It's recommend to use DDH-safe groups for DH-exchanges.
func IsSafePrimeGroup(g *Group, n int) bool {
q := new(big.Int).Sub(g.P, one)
q = q.Div(q, two)
return q.ProbablyPrime(n)
}
// PublicKey is the type of DH public keys.
type PublicKey *big.Int
// PrivateKey is the type of DH private keys.
type PrivateKey *big.Int
// Group represents a mathematical group defined
// by a large prime and a generator.
type Group struct {
P *big.Int // The prime
G *big.Int // The generator
}
// GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used.
func (g *Group) GenerateKey(rand io.Reader) (private PrivateKey, public PublicKey, err error) {
if g.P == nil {
panic("crypto/dh: group prime is nil")
}
if g.G == nil {
panic("crypto/dh: group generator is nil")
}
if rand == nil {
rand = cryptorand.Reader
}
// Ensure, that p.G ^ privateKey > than g.P
// (only modulo calculations are safe)
// The minimal (and common) value for p.G is 2
// So 2 ^ (1 + 'bitsize of p.G') > than g.P
min := big.NewInt(int64(g.P.BitLen() + 1)) //生成一个不小于p的大数
bytes := make([]byte, (g.P.BitLen()+7)/8) //bit/8 = byte, +7 是为了补空,放置少除了,然后长度不够
for private == nil {
_, err = io.ReadFull(rand, bytes)
if err != nil {
private = nil
return
}
// Clear bits in the first byte to increase
// the probability that the candidate is < g.P.
bytes[0] = 0
if private == nil {
private = new(big.Int)
}
(*private).SetBytes(bytes) //将读到的数据设置进private中
if (*private).Cmp(min) < 0 { //private 小于 一个不小于p的数。 如x < y返回-1;如x > y返回+1;否则返回0。
private = nil
}
}
public = new(big.Int).Exp(g.G, private, g.P) //x**y mod |m| = A = g**a mod p
return
}
// PublicKey returns the public key corresponding to the given private one.
func (g *Group) PublicKey(private PrivateKey) (public PublicKey) {
public = new(big.Int).Exp(g.G, private, g.P)
return
}
//private returns a non-nil error if the given public key is
// not a possible element of the group. This means, that the
// public key is < 0 or > g.P.
func (g *Group) Check(peersPublic PublicKey) (err error) {
if !((*peersPublic).Cmp(zero) >= 0 && (*peersPublic).Cmp(g.P) == -1) {
err = errors.New("peer's public is not a possible group element")
}
return
}
// ComputeSecret returns the secret computed from
// the own private and the peer's public key.
func (g *Group) ComputeSecret(private PrivateKey, peersPublic PublicKey) (secret *big.Int) {
secret = new(big.Int).Exp(peersPublic, private, g.P)
return
}
全称是Elliptic Curve Diffie-Hellman, 是DH算法的加强版, 基于椭圆曲线难题加密, 现在是主流的密钥交换算法。
ECC是建立在基于椭圆曲线的离散对数的难度, 大概过程如下:
给定椭圆曲线上的一个点P,一个整数k,求解Q=kP很容易;给定一个点P、Q,知道Q=kP,求整数k确是一个难题。ECDH即建立在此数学难题之上
package main
import (
"crypto"
"crypto/elliptic"
"crypto/rand"
"fmt"
"io"
"math/big"
"golang.org/x/crypto/curve25519"
)
// ECDH 秘钥交换算法的主接口
type ECDH interface {
GenerateKey(io.Reader) (crypto.PrivateKey, crypto.PublicKey, error)
Marshal(crypto.PublicKey) []byte
Unmarshal([]byte) (crypto.PublicKey, bool)
GenerateSharedSecret(crypto.PrivateKey, crypto.PublicKey) ([]byte, error)
}
type ellipticECDH struct {
ECDH
curve elliptic.Curve
}
type ellipticPublicKey struct {
elliptic.Curve
X, Y *big.Int
}
type ellipticPrivateKey struct {
D []byte
}
// NewEllipticECDH 指定一种椭圆曲线算法用于创建一个ECDH的实例
// 关于椭圆曲线算法标准库里面实现了4种: 见crypto/elliptic
func NewEllipticECDH(curve elliptic.Curve) ECDH {
return &ellipticECDH{
curve: curve,
}
}
// GenerateKey 基于标准库的NIST椭圆曲线算法生成秘钥对
func (e *ellipticECDH) GenerateKey(rand io.Reader) (crypto.PrivateKey, crypto.PublicKey, error) {
var d []byte
var x, y *big.Int
var priv *ellipticPrivateKey
var pub *ellipticPublicKey
var err error
d, x, y, err = elliptic.GenerateKey(e.curve, rand)
if err != nil {
return nil, nil, err
}
priv = &ellipticPrivateKey{
D: d,
}
pub = &ellipticPublicKey{
Curve: e.curve,
X: x,
Y: y,
}
return priv, pub, nil
}
// Marshal用于公钥的序列化
func (e *ellipticECDH) Marshal(p crypto.PublicKey) []byte {
pub := p.(*ellipticPublicKey)
return elliptic.Marshal(e.curve, pub.X, pub.Y)
}
// Unmarshal用于公钥的反序列化
func (e *ellipticECDH) Unmarshal(data []byte) (crypto.PublicKey, bool) {
var key *ellipticPublicKey
var x, y *big.Int
x, y = elliptic.Unmarshal(e.curve, data)
if x == nil || y == nil {
return key, false
}
key = &ellipticPublicKey{
Curve: e.curve,
X: x,
Y: y,
}
return key, true
}
// GenerateSharedSecret 通过自己的私钥和对方的公钥协商一个共享密码
func (e *ellipticECDH) GenerateSharedSecret(privKey crypto.PrivateKey, pubKey crypto.PublicKey) ([]byte, error) {
priv := privKey.(*ellipticPrivateKey)
pub := pubKey.(*ellipticPublicKey)
x, _ := e.curve.ScalarMult(pub.X, pub.Y, priv.D)
return x.Bytes(), nil
}
// NewCurve25519ECDH 使用密码学家Daniel J. Bernstein的椭圆曲线算法:Curve25519来创建ECDH实例
// 因为Curve25519独立于NIST之外, 没在标准库实现, 需要单独为期实现一套接口来支持ECDH
func NewCurve25519ECDH() ECDH {
return &curve25519ECDH{}
}
type curve25519ECDH struct {
ECDH
}
// GenerateKey 基于curve25519椭圆曲线算法生成秘钥对
func (e *curve25519ECDH) GenerateKey(rand io.Reader) (crypto.PrivateKey, crypto.PublicKey, error) {
var pub, priv [32]byte
var err error
_, err = io.ReadFull(rand, priv[:])
if err != nil {
return nil, nil, err
}
priv[0] &= 248
priv[31] &= 127
priv[31] |= 64
curve25519.ScalarBaseMult(&pub, &priv)
return &priv, &pub, nil
}
// 实现公钥的序列化
func (e *curve25519ECDH) Marshal(p crypto.PublicKey) []byte {
pub := p.(*[32]byte)
return pub[:]
}
// 实现公钥的反序列化
func (e *curve25519ECDH) Unmarshal(data []byte) (crypto.PublicKey, bool) {
var pub [32]byte
if len(data) != 32 {
return nil, false
}
copy(pub[:], data)
return &pub, true
}
// 实现秘钥协商接口
func (e *curve25519ECDH) GenerateSharedSecret(privKey crypto.PrivateKey, pubKey crypto.PublicKey) ([]byte, error) {
var priv, pub, secret *[32]byte
priv = privKey.(*[32]byte)
pub = pubKey.(*[32]byte)
secret = new([32]byte)
curve25519.ScalarMult(secret, priv, pub)
return secret[:], nil
}
func test(e ECDH) {
var privKey1, privKey2 crypto.PrivateKey
var pubKey1, pubKey2 crypto.PublicKey
var pubKey1Buf, pubKey2Buf []byte
var err error
var ok bool
var secret1, secret2 []byte
// 准备2对秘钥对,A: privKey1,pubKey1 B:privKey2,pubKey2
privKey1, pubKey1, err = e.GenerateKey(rand.Reader)
if err != nil {
fmt.Println(err)
}
privKey2, pubKey2, err = e.GenerateKey(rand.Reader)
if err != nil {
fmt.Println(err)
}
pubKey1Buf = e.Marshal(pubKey1)
pubKey2Buf = e.Marshal(pubKey2)
pubKey1, ok = e.Unmarshal(pubKey1Buf)
if !ok {
fmt.Println("Unmarshal does not work")
}
pubKey2, ok = e.Unmarshal(pubKey2Buf)
if !ok {
fmt.Println("Unmarshal does not work")
}
// A 通过B给的公钥协商共享密码
secret1, err = e.GenerateSharedSecret(privKey1, pubKey2)
if err != nil {
fmt.Println(err)
}
// B 通过A给的公钥协商共享密码
secret2, err = e.GenerateSharedSecret(privKey2, pubKey1)
if err != nil {
fmt.Println(err)
}
// A B在没暴露直接的私钥的情况下, 协商出了一个共享密码
fmt.Printf("The secret1 shared keys: %x\n", secret1)
fmt.Printf("The secret2 shared keys: %x\n", secret2)
}
func main() {
e1 := NewEllipticECDH(elliptic.P521())
e2 := NewCurve25519ECDH()
test(e1)
test(e2)