RSA算法(不要求支持大数)

题目描述

C++中数据的类型与长度参考:(这里没显示,大概告诉你64位机器longlong8字节)

因此,C++最大能支持的十进制是19位的整数。如果要支持更大的整数,需要实现Big Number类。RSA目前比较安全的密钥长度是2048位二进制,即是617位的十进制。因此,C++自带的数据类型无法实现安全的RSA密钥加解密。

为了降低难度,该题不要求实现大数支持,因此只使用C++自带的long long 数据类型。

该实验主要包含三部分:1. 公私钥的生成。
在公私钥生成中,有p、q、e三个参数是随机选择的,其中p、q要求是质数,因此需要实现一个函数检查一个整数是否是质数。
由p、q的乘积可以得到n:n=p*q,以及n的欧拉函数: φ(n) = (p-1)*(q-1)。

e是在(1, φ(n))之间随机选取的整数,需要满足gcd(e, φ(n)) = 1,因此,需要通过扩展欧几里得算法验证取得的e是与φ(n)互质的。d可以通过扩展欧几里得算法求得 。以满足

,即

公钥为(n, e),私钥为(n,d)

检查一个整数是否为质数-Rabin-Miller算法,请参考:https://blog.csdn.net/ECNU_LZJ/article/details/72675595https://www.cnblogs.com/zwfymqz/p/8150969.htmlhttps://www.cnblogs.com/zwfymqz/p/8150861.html

扩展欧几里得算法:请参考:https://blog.csdn.net/u014117943/article/details/108428551

2. 加密过程,使用加密算法c = m^e mod n,计算出密文c;

3.解密过程,使用私钥d和解密算法m = c^d mod n, ,计算m;

加密和解密过程需要做幂运算取余,如果直接先做幂运算再取余,则很容易出现溢出,因此,我们需要采用快速幂运算取余算法,请参考:https://jlice.top/p/7tbs7/

因此,该次实验主要难点在于以下三个算法的理解与实现:

1. Rabin-Miller算法

2. 扩展欧几里得算法

3. 快速幂取余算法

根据前面的算法,我们知道明文和密文都不能大于n,假设n的长度为L,对于明文,我们需要按照L-1的长度对其分组然后再加密,每组的密文长度L。解密的时候使用L的长度对其进行分组然后解密,每组的明文长度为L-1。分组按照整数从低到高(即从右往左)

输入

第一行是p

第二行是q

第三行是e

第四行是待加密数据

第五行是待解密数据

输出

第一行输出p是否是质数

第二行输出q是否是质数

第三行打印n

第四行打印d

第五行显示输入第四行的加密结果

第六行显示输入第五行的解密结果

输入样例1

67
43
13
281
2154

输出样例1

Yes
Yes
2881
853
325
54

输入样例2

67
43
13
54281
3252154

输出样例2

Yes
Yes
2881
853
21540325
281054

输入样例3

11
17
7
88
11

输出样例3

Yes
Yes
187
23
11
88

解题

题目就是一个精简的RSA算法,由于题目强调没有大数,所以甚至用不到Go的math/big
最核心的三个算法在题目描述中已经告诉我们了

1. Rabin-Miller算法,判断一个数是否为质数
2. 扩展欧几里得算法,算逆元
3. 快速幂取余算法,低于O(n)的求幂算法

其实,还有一块我得强调,也是我一开始没有看到的地方
就是题目描述最后的地方,当待加密的内容m与待解密的内容c大于n时,需要分组。
可以这样实现:

func buwei(num, wei int64) string {
    return fmt.Sprintf("%0*d", wei, num)
}

然后判断一个数是否为质数,用到的Miller-Rabin算法
没错,我没打反,因为它就叫做这个名字

func Prime(n, trials int64) bool {
    if n < 2 {
        return false
    }

    var i int64
    for ; i < trials; i++ {
        r := rand.Intn(int(n)-1) + 1
        if mrCompositeWitness(int64(r), n) {
            return false
        }
    }
    return true
}
func mrCompositeWitness(a, n int64) bool {
    theBits := bits(n - 1)
    var rem int64 = 1
    for i := len(theBits) - 1; i >= 0; i-- {
        x := rem
        rem = (rem * rem) % n

        if rem == 1 && x != 1 && x != n-1 {
            return true
        }

        if theBits[i] == 1 {
            rem = (rem * a) % n
        }

    }
    if rem != 1 {
        return true
    }
    return false
}
func bits(n int64) []int64 {
    var bits []int64
    for ; n > 0; n = n >> 1 {
        bits = append(bits, n%2)
    }
    return bits
}

求逆元的拓展欧几里得算法,我写在函数里

var exgcd func(a, b int64) (gcd, x, y int64)
exgcd = func(a, b int64) (gcd, x, y int64) {
        if b == 0 {
            return a, 1, 0
        }
        gcd, y, x = exgcd(b, a%b)
        y -= a / b * x
        return
    }

快速幂取模

func quic(c,d,n int64) int64 {
    var ans int64 = 1
    for d!=0 {
        if d&0x1!=0 {
            ans = (ans*c)%n
        }
        c = (c*c) %n
        d >>= 1
    }
    return ans
}

完整的代码如下,我就不加注释了

package main

import (
    "bufio"
    "fmt"
    "io"
    "math/rand"
    "os"
    "strconv"
)

const DefaultTrials = 6

func bits(n int64) []int64 {
    var bits []int64
    for ; n > 0; n = n >> 1 {
        bits = append(bits, n%2)
    }
    return bits
}

func mrCompositeWitness(a, n int64) bool {
    theBits := bits(n - 1)
    var rem int64 = 1
    for i := len(theBits) - 1; i >= 0; i-- {
        x := rem
        rem = (rem * rem) % n

        if rem == 1 && x != 1 && x != n-1 {
            return true
        }

        if theBits[i] == 1 {
            rem = (rem * a) % n
        }

    }
    if rem != 1 {
        return true
    }
    return false
}

func Prime(n, trials int64) bool {
    if n < 2 {
        return false
    }

    var i int64
    for ; i < trials; i++ {
        r := rand.Intn(int(n)-1) + 1
        if mrCompositeWitness(int64(r), n) {
            return false
        }
    }
    return true
}
func check(num int64) {
    if Prime(num,DefaultTrials) {
        fmt.Println("Yes")
    }else {
        fmt.Println("No")
    }
}
func qpow(a, b int64) int64 {
    var ans int64 = 1
    p := b+2
    a = (a%p + p) % p
    for ; b != 0; b >>= 1 {
        if b&1 != 0 {
            ans = (a * ans) % p
        }
        a = a * a % p
    }
    return ans
}
func buwei(num, wei int64) string {
    return fmt.Sprintf("%0*d", wei, num)
}
func make_Key(m, e, n int64) string {
    if m<n {
        return strconv.Itoa(int(quic(m,e,n)))
    }
    if m < n {
        return strconv.Itoa(int(quic(m, e, n)))
    }
    length := len(strconv.Itoa(int(n))) - 1
    var wei int64 = 1
    for i := 0; i < length; i++ {
        wei *= 10
    }
    ans := ""
    for m != 0 {
        ans = buwei(quic(m%wei, e, n), int64(length)+1) + ans
        m /= wei
    }
    return ans
}
func de_Key(c, d, n int64) string {
    if c<n {
        return strconv.Itoa(int(quic(c,d,n)))
    }
    length := len(strconv.Itoa(int(n)))

    var wei int64 = 1
    for i := 0; i < length; i++ {
        wei *= 10
    }
    ans := ""
    for c != 0 {
        ans = buwei(quic(c%wei, d, n),int64(length-1)) + ans
        c /= wei
    }
    return ans
}
func quic(c,d,n int64) int64 {
    var ans int64 = 1
    for d!=0 {
        if d&0x1!=0 {
            ans = (ans*c)%n
        }
        c = (c*c) %n
        d >>= 1
    }
    return ans
}
func id194(_r io.Reader, _w io.Writer) {
    in := bufio.NewReader(_r)
    out := bufio.NewWriter(_w)
    defer out.Flush()

    var p,q,e,m,c int64
    fmt.Fscan(in,&p,&q,&e,&m,&c)
    check(p)
    check(q)
    fmt.Println(p*q)
    fai_n := (p-1)*(q-1)
    var exgcd func(a, b int64) (gcd, x, y int64)
    exgcd = func(a, b int64) (gcd, x, y int64) {
        if b == 0 {
            return a, 1, 0
        }
        gcd, y, x = exgcd(b, a%b)
        y -= a / b * x
        return
    }
    _,d,_ := exgcd(e,fai_n)
    fmt.Println(d)
    fmt.Println(make_Key(m,e,p*q))
    fmt.Println(de_Key(c,d,p*q))
}
func main() {
    id194(os.Stdin, os.Stdout)
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容