密码学—RSA(非对称加密)

RSA

RSA加密利用了单向函数正向求解很简单,反向求解很复杂的特性
在这里插入图片描述


基本概念

在这里插入图片描述
一、 什么是“素数”?
  素数是这样的整数,它除了能表示为它自己和1的乘积以外,不能表示为任何其它两个整数的乘积。例如,15=3*5,所以15不是素数;又如,12=6*2=4*3,所以12也不是素数。另一方面,13除了等于13*1以外,不能表示为其它任何两个整数的乘积,所以13是一个素数。素数也称为“质数”。

二、什么是“互质数”(或“互素数”)?
  小学数学教材对互质数是这样定义的:“公约数只有1的两个数,叫做互质数。”这里所说的“两个数”是指自然数。
  判别方法主要有以下几种(不限于此):
(1)两个质数一定是互质数。例如,2与7、13与19。
(2)一个质数如果不能整除另一个合数,这两个数为互质数。例如,3与10、5与 26。
(3)1不是质数也不是合数,它和任何一个自然数在一起都是互质数。如1和9908。
(4)相邻的两个自然数是互质数。如 15与 16。
(5)相邻的两个奇数是互质数。如 49与 51。
(6)大数是质数的两个数是互质数。如97与88。
(7)小数是质数,大数不是小数的倍数的两个数是互质数。如 7和 16。
(8)两个数都是合数(二数差又较大),小数所有的质因数,都不是大数的约数,这两个数是互质数。如357与715,357=3×7×17,而3、7和17都不是715的约数,这两个数为互质数。等等。

三、什么是模指数运算?
  指数运算谁都懂,不必说了,先说说模运算。模运算是整数运算,有一个整数m,以n为模做模运算,即m mod n。怎样做呢?让m去被n整除,只取所得的余数作为结果,就叫做模运算。例如,10 mod 3=1;26 mod 6=2;28 mod 2 =0等等。
  模指数运算就是先做指数运算,取其结果再做模运算。如(5^3) mod 7 = (125 mod 7) = 6。

RSA加解密


RSA属于公钥加密算法中的一个重要应用。RSA加密算法由五个部分组成:

  • 原文(Message):需要加密的信息,可以是数字、文字、视频、音频等,用 M M M 表示。
  • 密文(Ciphertext):加密后得到的信息,用 C C C表示。
  • 公钥(Public Key)和私钥(Secret Key),用 P K PK PK S K SK SK表示。
  • 加密算法(Encryption):若 E ( x ) E(x) E(x) 为加密算法,加密过程可以理解为 C = E ( M ) C = E(M) C=E(M)根据原文和加密算法得到密文。
  • 解密算法(Decryption):若 D ( x ) D(x) D(x)为解密算法,解密过程可以理解为 M = D ( C ) M = D(C) M=D(C)据密文和解密算法得到原文。

假设Alice和Bob要在网上进行加密通信,他们要怎么应用RSA来加密和解密信息呢?步骤如下:

  1. 随机选择两个不相同的素数 p , q p,q p,q
  2. p , q p,q p,q相乘,记为 n = p × q n = p\times q n=p×q
  3. 计算 n n n的欧拉函数 φ ( n ) \varphi(n) φ(n) ,欧拉函数证明,当 p , q p,q p,q为不相同的素数时, φ ( n ) = ( p − 1 ) ( q − 1 ) \varphi(n)=(p-1)(q-1) φ(n)=(p1)(q1)
  4. 随机选择一个整数 e e e,满足两个条件: φ ( n ) \varphi(n) φ(n) e e e互质,且 1 < e < φ ( n ) 1<e<\varphi(n) 1<e<φ(n)
  5. 计算 e e e对于 φ ( n ) \varphi(n) φ(n) 的模反元素 d d d,也就是说找到一个 d d d满足 e d = 1 m o d φ ( n ) ed = 1 mod\varphi(n) ed=1modφ(n)。这个式子等价于 e d − 1 = k φ ( n ) ed-1 = k\varphi(n) ed1=kφ(n),实际上就是对于方程 e d − k φ ( n ) = 1 ed-k\varphi(n) = 1 edkφ(n)=1 ( d , k ) (d,k) (d,k)的整数解。这个方程可以用扩展欧几里得算法求解。
  6. 最终把 ( e , n ) (e,n) (e,n)封装成公钥, ( d , n ) (d,n) (d,n)封装成私钥。

我们举个实际例子运行一遍这个算法。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

RSA算法

Java版本

package com.tencent.blue.utils;

import org.apache.tomcat.util.codec.binary.Base64;
import org.apache.tomcat.util.http.fileupload.IOUtils;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by cuiran on 19/1/9.
 */
public class RSAUtils {
    
    

    public static final String CHARSET = "UTF-8";
    public static final String RSA_ALGORITHM = "RSA";


    public static Map<String, String> createKeys(int keySize){
    
    
        //为RSA算法创建一个KeyPairGenerator对象
        KeyPairGenerator kpg;
        try{
    
    
            kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        }catch(NoSuchAlgorithmException e){
    
    
            throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");
        }

        //初始化KeyPairGenerator对象,密钥长度
        kpg.initialize(keySize);
        //生成密匙对
        KeyPair keyPair = kpg.generateKeyPair();
        //得到公钥
        Key publicKey = keyPair.getPublic();
        String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
        //得到私钥
        Key privateKey = keyPair.getPrivate();
        String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());
        Map<String, String> keyPairMap = new HashMap<String, String>();
        keyPairMap.put("publicKey", publicKeyStr);
        keyPairMap.put("privateKey", privateKeyStr);

        return keyPairMap;
    }

    /**
     * 得到公钥
     * @param publicKey 密钥字符串(经过base64编码)
     * @throws Exception
     */
    public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    
    
        //通过X509编码的Key指令获得公钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
        return key;
    }

    /**
     * 得到私钥
     * @param privateKey 密钥字符串(经过base64编码)
     * @throws Exception
     */
    public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    
    
        //通过PKCS#8编码的Key指令获得私钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
        RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
        return key;
    }

    /**
     * 公钥加密
     * @param data
     * @param publicKey
     * @return
     */
    public static String publicEncrypt(String data, RSAPublicKey publicKey){
    
    
        try{
    
    
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength()));
        }catch(Exception e){
    
    
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 私钥解密
     * @param data
     * @param privateKey
     * @return
     */

    public static String privateDecrypt(String data, RSAPrivateKey privateKey){
    
    
        try{
    
    
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), CHARSET);
        }catch(Exception e){
    
    
            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 私钥加密
     * @param data
     * @param privateKey
     * @return
     */

    public static String privateEncrypt(String data, RSAPrivateKey privateKey){
    
    
        try{
    
    
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength()));
        }catch(Exception e){
    
    
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 公钥解密
     * @param data
     * @param publicKey
     * @return
     */

    public static String publicDecrypt(String data, RSAPublicKey publicKey){
    
    
        try{
    
    
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), CHARSET);
        }catch(Exception e){
    
    
            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
        }
    }

    private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize){
    
    
        int maxBlock = 0;
        if(opmode == Cipher.DECRYPT_MODE){
    
    
            maxBlock = keySize / 8;
        }else{
    
    
            maxBlock = keySize / 8 - 11;
        }
        ByteArrayOutputStream
                out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] buff;
        int i = 0;
        try{
    
    
            while(datas.length > offSet){
    
    
                if(datas.length-offSet > maxBlock){
    
    
                    buff = cipher.doFinal(datas, offSet, maxBlock);
                }else{
    
    
                    buff = cipher.doFinal(datas, offSet, datas.length-offSet);
                }
                out.write(buff, 0, buff.length);
                i++;
                offSet = i * maxBlock;
            }
        }catch(Exception e){
    
    
            throw new RuntimeException("加解密阀值为["+maxBlock+"]的数据时发生异常", e);
        }
        byte[] resultDatas = out.toByteArray();
        IOUtils.closeQuietly(out);
        return resultDatas;
    }

    public static void main (String[] args) throws Exception {
    
    
        Map<String, String> keyMap = RSAUtils.createKeys(1024);
        String  publicKey = keyMap.get("publicKey");
        String  privateKey = keyMap.get("privateKey");
        System.out.println("公钥: \n\r" + publicKey);
        System.out.println("私钥: \n\r" + privateKey);

        System.out.println("公钥加密——私钥解密");
        String str = "code_cayden";
        System.out.println("\r明文:\r\n" + str);
        System.out.println("\r明文大小:\r\n" + str.getBytes().length);
        String encodedData = RSAUtils.publicEncrypt(str, RSAUtils.getPublicKey(publicKey));
        System.out.println("密文:\r\n" + encodedData);
        String decodedData = RSAUtils.privateDecrypt(encodedData, RSAUtils.getPrivateKey(privateKey));
        System.out.println("解密后文字: \r\n" + decodedData);


    }


}

C++

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include<string.h>
#include <math.h>
#include<algorithm>
using namespace std;
typedef long long ll;
int e, d, n;

int gcd(int a, int b)  //求最大公约数
{
    
    
    int c = 0;
    if(a<b) swap(a,b);
    c = b;
    do
    {
    
    
        b = c;
        c = a%b;
        a = b;
    }
    while (c != 0);
    return b;
}

int PrimarityTest(int a, int i) //判断i是否是素数
{
    
    
    int flag=0;
    for(a;a<i;a++)
    {
    
    
        if(i%a==0)
        {
    
    
            flag=1;
            break;
        }
    }
    if(flag) return 0;
    return 1;
    // complete this part
}

int ModularExponention(int a, int b, int n)  //求a^bmodn
{
    
    
    int y;

    /*使用二进制平方乘法计算 pow(a,b) % n*/
    y=1;

    while(b != 0)
    {
    
    
        /*对于b中的每个1,累加y*/

        if(b & 1)
            y = (y*a) % n;

        /*对于b中的每一位,计算a的平方*/
        a = (a*a) % n;

        /*准备b中的下一位*/
        b = b>>1;
    }

    return y;
    // complete this part
}

void extgcd(ll a,ll b,ll& d,ll& x,ll& y) //获取(1/a)modb得结果
{
    
    
    if(!b)
    {
    
    
        d=a;
        x=1;
        y=0;
    }
    else
    {
    
    
        extgcd(b,a%b,d,y,x);
        y-=x*(a/b);
    }
}

int ModularInverse(int a,int b)  //获取(1/a)modb得结果
{
    
    
    ll d,x,y;
    extgcd(a,b,d,x,y);
    return d==1?(x+b)%b:-1;
    // complete this part
}

void KeyGeneration()  //获取公钥密钥
{
    
    
    int p, q;
    int phi_n;

    do
    {
    
    
        do
            p = rand();
        while (p % 2 == 0);

    }
    while (!PrimarityTest(2, p));

    do
    {
    
    
        do
            q = rand();
        while (q % 2 == 0);
    }
    while (!PrimarityTest(2, q));

    n = p * q;
    phi_n = (p - 1) * (q - 1);

    do
        e = rand() % (phi_n - 2) + 2; // 1 < e < phi_n
    while (gcd(e, phi_n) != 1);

    d = ModularInverse(e,phi_n);
}

void Encryption(int value, FILE* out)  //加密
{
    
    
    int cipher;
    cipher = ModularExponention(value, e, n);
    fprintf(out, "%d ", cipher);
}

void Decryption(int value, FILE* out)  //解密
{
    
    
    int decipher;
    decipher = ModularExponention(value, d, n);
    fprintf(out, "%c", decipher);
}
int main(void)
{
    
    
    FILE* inp, * out;
    char filepath[15], filename[100];

    strcpy(filepath, "F:\Desktop\\");  //文件路径

    sprintf(filename, "%s%s", filepath, "cipher.txt");
    out = fopen(filename, "w+");  //打开文件
    fclose(out);
    sprintf(filename, "%s%s", filepath, "decipher.txt");
    out = fopen(filename, "w+");  //打开文件
    fclose(out);

    KeyGeneration();  //获取公钥密钥

    sprintf(filename, "%s%s", filepath, "plain.txt");
    inp = fopen(filename, "r+");  //读取原文件
    if (inp == NULL)
    {
    
    
        printf("Error opening Source File.\n");
        exit(1);
    }

    sprintf(filename, "%s%s", filepath, "cipher.txt");
    out = fopen(filename, "w+");
    if (out == NULL)
    {
    
    
        printf("Error opening Destination File.\n");
        exit(1);
    }

    // encryption starts
    while (1)
    {
    
    
        char ch = getc(inp);  //读取文件字符,一个字符一个字符的读取输出
        if (ch == -1)
            break;
        int value = toascii(ch);  //toascii将字符转化成对应ascall值
        Encryption(value, out);  //加密输出
    }

    fclose(inp);
    fclose(out);

    // decryption starts
    sprintf(filename, "%s%s", filepath, "cipher.txt");
    inp = fopen(filename, "r");
    if (inp == NULL)
    {
    
    
        printf("Error opening Cipher Text.\n");
        exit(1);
    }

    sprintf(filename, "%s%s", filepath, "decipher.txt");
    out = fopen(filename, "w+");
    if (out == NULL)
    {
    
    
        printf("Error opening File.\n");
        exit(1);
    }

    while (1)
    {
    
    
        int cip;
        if (fscanf(inp, "%d", &cip) == -1)
            break;
        Decryption(cip, out);  //解密
    }
    fclose(out);

    return 0;
}

密码为什么一定要用到素数(质数)?

这个问题谁能回答我一下?

猜你喜欢

转载自blog.csdn.net/YM_1111/article/details/117899195