golang 实现简单的rsa加密算法

Golang 实现简单的rsa加密算法

NOTE:
  • gcd 是求最大公约数
  • Golang 中已经有crypto/rsa实现加密EncryptPKCS1v15()、解密DecryptPKCS1v15(),本文只是自己实现简单的ras 加密算法
rsa 算法
1. 选择两个 p,q 素数,n = p * q
 2. 计算 Q = (p-1) * (q-1)
 3. 找出满足条件的e:
    1 < e < Q, gcd(e,Q) = 1
    方法:
    	在 (1,Q) 中选择一个素数, 使 gcd(e,Q) = 1, 既使得 gcd(e,p-1) =1 && gcd(e,q-1) = 1
    推论:
    	gcd(e,Q) = 1 	=> 	gcd(e,p-1) = 1 && gcd(e,q-1) = 1
    	如:	gcd(4,7) = 1 && gcd(4,9) = 1 	=> 	gcd(4,36)
 4. 找出满足条件的d
    1< d < Q, ed % Q = 1 	=> 	1< Q/e < d < Q, ed % Q = 1
    方法:
    	 => (ed - 1)  / Q = 0
 5. 公钥: (n,e) , 私钥: (n,d) . p,q,Q 的值不公开
加密:

​ c = exp(m,e) % n

解密:

​ m = exp(c,d) % n

实现:
package rsa

import (
	"fmt"
	"math/big"
	"strings"
	"time"

	"github.com/feiquan123/algorithm/prime"
)

var rsa *RSA

func init() {
	rsa = New(0)
}

// GCD 求两个数的最大公约数
func GCD(m, n uint64) uint64 {
	if m < n {
		m, n = n, m
	}

	if n == 0 {
		return m
	}

	return GCD(n, m%n)
}

var split = "\xff\xfe\xff"

// PublicKey public key
type PublicKey struct {
	N uint64
	E uint64
}

// NewPublicKey new public key
func NewPublicKey(n, e uint64) *PublicKey {
	return &PublicKey{n, e}
}

// String get public key
func (p PublicKey) String() string {
	return fmt.Sprintf("%d,%d", p.N, p.E)
}

// Check check pubilc key
func (p PublicKey) Check() error {
	if p.N < 6 {
		return fmt.Errorf("public kye  error, N too small")
	}
	if p.E < 2 {
		return fmt.Errorf("public kye error, E too small")
	}
	return nil
}

// PrivateKey private key
type PrivateKey struct {
	N uint64
	D uint64
}

// NewPrivateKey creates a new private key
func NewPrivateKey(n, d uint64) *PrivateKey {
	return &PrivateKey{n, d}
}

// String get private key
func (p PrivateKey) String() string {
	return fmt.Sprintf("%d,%d", p.N, p.D)
}

// Check check private key
func (p PrivateKey) Check() error {
	if p.N < 6 {
		return fmt.Errorf("public kye  error, N too small")
	}
	if p.D < 2 {
		return fmt.Errorf("public kye error, E too small")
	}
	return nil
}

// RSA msg encode and decode
type RSA struct {
	p uint64
	q uint64
	o uint64

	N uint64
	E uint64
	D uint64

	pub PublicKey
	pri PrivateKey
}

// New creates a new RSA
func New(N uint64) *RSA {
	n := time.Now().UnixNano()/1e6%(1000+int64(N)) + 13
	ps := prime.NPrimeEratosthenes(uint64(n))
	l := len(ps)
	if l == 0 {
		panic(fmt.Sprintf("l is 0, n=%d", n))
	}
	psm := make(map[uint64]struct{}, l)
	for _, v := range ps {
		psm[v] = struct{}{}
	}

	p, q := uint64(0), uint64(0)
	for k := range psm {
		if k < 5 {
			continue
		}
		p = k
	}
	for k := range psm {
		if k < 5 || k == p {
			continue
		}
		q = k
	}

	rsa := &RSA{
		p: p,
		q: q,
		o: (p - 1) * (q - 1),
		N: p * q,
	}

	tps := prime.NPrimeEratosthenes(rsa.o)
	tpsm := make(map[uint64]struct{}, len(tps))
	for _, t := range tps {
		tpsm[t] = struct{}{}
	}
	for t := range tpsm {
		if GCD(t, p-1) == 1 && GCD(t, q-1) == 1 {
			rsa.E = t
			break
		}
	}

	for i := rsa.o / rsa.E; i < rsa.o; i++ {
		if rsa.E*i%rsa.o == 1 {
			rsa.D = i
			break
		}
	}

	rsa.pub = PublicKey{N: rsa.N, E: rsa.E}
	rsa.pri = PrivateKey{N: rsa.N, D: rsa.D}

	return rsa
}

func (r RSA) PublicKey() string {
	return r.pub.String()
}

func (r RSA) PrivateKey() string {
	return r.pri.String()
}

// Encode encode bytes
func Encode(bs []byte, pub *PublicKey) (c []byte) { return rsa.Encode(bs, pub) }
func (r RSA) Encode(bs []byte, pub *PublicKey) (be []byte) {
	e, n := r.E, r.N
	if pub != nil && pub.Check() == nil {
		e = pub.E
		n = pub.N
	}
	bet := make([]string, 0)
	for _, b := range bs {
		m := new(big.Int).SetBytes([]byte{b})                                // source
		c := new(big.Int).Exp(m, big.NewInt(int64(e)), big.NewInt(int64(n))) // encode: m ** e % n
		bet = append(bet, string(c.Bytes()))
	}
	return []byte(strings.Join(bet, split))
}

// Decode decode bytes
func Decode(be []byte, pri *PrivateKey) (bs []byte, err error) { return rsa.Decode(be, pri) }
func (r RSA) Decode(be []byte, pri *PrivateKey) (bs []byte, err error) {
	d, n := r.D, r.N
	if pri != nil && pri.Check() == nil {
		d = pri.D
		n = pri.N
	}

	bs = make([]byte, 0)
	for _, b := range strings.Split(string(be), split) {
		c := new(big.Int).SetBytes([]byte(b))                                // encode
		m := new(big.Int).Exp(c, big.NewInt(int64(d)), big.NewInt(int64(n))) // decode: c ** d % n
		bs = append(bs, m.Bytes()[0])
	}

	return bs, nil
}
安装
go install github.com/feiquan123/algorithm/example/rsa
测试
  1. 生成key

    rsa -gen
    
    public  key: 474731,172867
    private key: 474731,356659
    
  2. 加密string

    echo "GOLANG" | rsa -pub 474731,172867
    
    �����[����#����������9����������
    
  3. 解密string

    echo "GOLANG" | rsa -pub 474731,172867 | rsa -e=false -pri=474731,356659 
    
    GOLANG
    
  4. 加密文件

    rsa -pub 474731,172867  -f go.mod
    
    ����������Ψ�������������X����R����:������M��������������U���x����/����������������������X�������4�������������ԧ���+-���y�����������������������:��������5�������M������������������������:��������R����+-���x����+-���Ŧ�������������5����X����4�����������5����X����R����:������M��������������U���x����/������������������zm�������������5����M���������zm���M����5����X����X����M����zm��������:��������/��������ԧ����X���X���������R�����X���+-���x���������x����Ŧ�����
    
  5. 解密文件

    rsa -pub 474731,172867  -f go.mod | rsa -e=false -pri=474731,356659 
    
    module github.com/feiquan123/algorithm
    
    go 1.14
    
    require github.com/smartystreets/goconvey v1.6.4
    
posted @ 2021-01-14 22:34  feiquan  阅读(349)  评论(0编辑  收藏  举报
如果是此文是转载文章,本人会附上转载链接,此篇文章的版权归原创作者所属,如果侵权请与我联系,我会删除此文。

若没有标明转载链接,此篇文章属于本人的原创文章,其版权所属:
作者:feiquan
出处:http://www.cnblogs.com/feiquan/
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
大家写文都不容易,请尊重劳动成果~ 这里谢谢大家啦(*/ω\*)