exponent modulus 根据_RSA算法使用介绍

http://www.cnblogs.com/AloneSword/p/3326750.html

RSA是目前最有影响力的公钥加密算法,该算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数组合成私钥。公钥是可发布的供任何人使用,私钥则为自己所有,供解密之用。

解密者拥有私钥,并且将由私钥计算生成的公钥发布给加密者。加密都使用公钥进行加密,并将密文发送到解密者,解密者用私钥解密将密文解码为明文。

以甲要把信息发给乙为例,首先确定角色:甲为加密者,乙为解密者。首先由乙随机确定一个KEY,称之为密匙,将这个KEY始终保存在机器B中而不发出来;然后,由这个 KEY计算出另一个KEY,称之为公匙。这个公钥的特性是几乎不可能通过它自身计算出生成它的私钥。接下来通过网络把这个公钥传给甲,甲收到公钥后,利用公钥对信息加密,并把密文通过网络发送到乙,最后乙利用已知的私钥,就对密文进行解码了。以上就是RSA算法的工作流程。

算法实现过程为:

1. 随意选择两个大的质数p和q,p不等于q,计算N=pq。

2. 根据欧拉函数,不大于N且与N互质的整数個数為(p-1)(q-1)。

3. 选择一个整数e与(p-1)(q-1)互质,并且e小于(p-1)(q-1)。

4. 用以下这个公式计算d:d× e ≡ 1 (mod (p-1)(q-1))。

5. 将p和q的记录销毁。

以上内容中,(N,e)是公钥,(N,d)是私钥。

下面讲解RSA算法的应用。

RSA的公钥和私钥是由KeyPairGenerator生成的,获取KeyPairGenerator的实例后还需要设置其密钥位数。设置密钥位数越高,加密过程越安全,一般使用1024位。如下代码:

[代码]java代码:

1

KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);

2

// 密钥位数

3

keyPairGen.initialize(1024);

公钥和私钥可以通过KeyPairGenerator执行generateKeyPair()后生成密钥对KeyPair,通过KeyPair.getPublic()和KeyPair.getPrivate()来获取。如下代码:

[代码]java代码:

1

// 动态生成密钥对,这是当前最耗时的操作,一般要2s以上。

2

KeyPair keyPair = keyPairGen.generateKeyPair();

3

// 公钥

4

PublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

5

// 私钥

6

PrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

7

byte[] publicKeyData = publicKey.getEncoded();

8

byte[] privateKeyData = publicKey.getEncoded();

公钥和私钥都有它们自己独特的比特编码,可以通过getEncoded()方法获取,返回类型为byte[]。通过byte[]可以再度将公钥或私钥还原出来。具体代码如下:

[代码]java代码:

01

// 通过公钥byte[]将公钥还原,适用于RSA算法

02

public static PublicKey getPublicKey(byte[] keyBytes)throws

03

NoSuchAlgorithmException,InvalidKeySpecException {

04

X509EncodedKeySpec keySpec =new X509EncodedKeySpec(keyBytes);

05

KeyFactory keyFactory = KeyFactory.getInstance("RSA");

06

PublicKey publicKey = keyFactory.generatePublic(keySpec);

07

return publicKey;

08

}

09

// 通过私钥byte[]将公钥还原,适用于RSA算法

10

public static PrivateKey getPrivateKey(byte[] keyBytes)throws

11

NoSuchAlgorithmException,InvalidKeySpecException {

12

PKCS8EncodedKeySpec keySpec =new PKCS8EncodedKeySpec(keyBytes);

13

KeyFactory keyFactory = KeyFactory.getInstance("RSA");

14

PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

15

return privateKey;

16

}

在上文讲到的RSA算法实现过程中提到(N,e)是公钥,(N,d)是私钥。既然已经获取到了PublicKey和PrivateKey了,那如何取到N、e、d这三个值呢。要取到这三个值,首先要将PublicKey和PrivateKey强制转换成RSAPublicKey和RSAPrivateKey。共同的N值可以通过getModulus()获取。执行RSAPublicKey.getPublicExponent()可以获取到公钥中的e值,执行RSAPrivateKey.getPrivateExponent()可以获取私钥中的d值。这三者返回类型都是BigInteger。代码如下:

[代码]java代码:

01

// 打印公钥信息

02

public static void printPublicKeyInfo(PublicKey key){

03

RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;

04

Log.d(MainActivity.TAG,"RSAPublicKey:");

05

Log.d(MainActivity.TAG,"Modulus.length=" +

06

rsaPublicKey.getModulus().bitLength());

07

Log.d(MainActivity.TAG,"Modulus=" +

08

rsaPublicKey.getModulus().toString());

09

Log.d(MainActivity.TAG,"PublicExponent.length=" +

10

rsaPublicKey.getPublicExponent().bitLength());

11

Log.d(MainActivity.TAG,"PublicExponent=" +

12

rsaPublicKey.getPublicExponent().toString());

13

}

14

15

// 打印私钥信息

16

public static void printPublicKeyInfo(PrivateKey key){

17

RSAPrivateKey rsaPublicKey = (RSAPrivateKey) privateKey;

18

Log.d(MainActivity.TAG,"RSAPrivateKey:");

19

Log.d(MainActivity.TAG,"Modulus.length=" +

20

rsaPrivateKey.getModulus().bitLength());

21

Log.d(MainActivity.TAG,"Modulus=" +

22

rsaPrivateKey.getModulus().toString());

23

Log.d(MainActivity.TAG,"PublicExponent.length=" +

24

rsaPrivateKey.getPrivateExponent().bitLength());

25

Log.d(MainActivity.TAG,"PublicExponent=" +

26

rsaPrivateKey.getPrivateExponent().toString());

27

}

由于程序中动态生成KeyPair对明文加密后生成的密文是不可测的,所以在实际开发中通常在生成一个KeyPair后将公钥和私钥的N、e、d这三个特征值记录下来,在真实的开发中使用这三个特征值再去将PublicKey和PrivateKey还原出来。还原方法如下:

[代码]java代码:

01

// 使用N、e值还原公钥

02

public static PublicKey getPublicKey(String modulus, String

03

publicExponent)

04

throws NoSuchAlgorithmException, InvalidKeySpecException {

05

BigInteger bigIntModulus =new BigInteger(modulus);

06

BigInteger bigIntPrivateExponent =new BigInteger(publicExponent);

07

RSAPublicKeySpec keySpec =new RSAPublicKeySpec(bigIntModulus,

08

bigIntPrivateExponent);

09

KeyFactory keyFactory = KeyFactory.getInstance("RSA");

10

PublicKey publicKey = keyFactory.generatePublic(keySpec);

11

return publicKey;

12

}

13

14

// 使用N、d值还原公钥

15

public static PrivateKey getPrivateKey(String modulus, String

16

privateExponent)

17

throws NoSuchAlgorithmException, InvalidKeySpecException {

18

BigInteger bigIntModulus =new BigInteger(modulus);

19

BigInteger bigIntPrivateExponent =new BigInteger(privateExponent);

20

RSAPrivateKeySpec keySpec =new RSAPrivateKeySpec(bigIntModulus,

21

bigIntPrivateExponent);

22

KeyFactory keyFactory = KeyFactory.getInstance("RSA");

23

PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

24

return privateKey;

25

}

公钥和私钥都具备后,就可以使用加解密的工具类javax.crypto.Cipher对明文和密文进行处理了。与所有的引擎类一样,可以通过调用Cipher类中的getInstance(String transformation)静态工厂方法得到Cipher对象。该方法中的参数描述了由指定输入产生输出所进行的操作或操作集合,可以是下列两种形式之一:“algorithm/mode/padding”或“algorithm”。例如下面的例子就是有效的transformation形式:"DES/CBC/PKCS5Padding"或"DES"。如果没有指定模式或填充方式,就使用特定提供者指定的默认模式或默认填充方式。

Cipher的加密和解密方式所调用的方法和过程都一样,只是传参不同的区别。如下代码:

[代码]java代码:

1

// 编码前设定编码方式及密钥

2

cipher.init(mode, key);

3

// 传入编码数据并返回编码结果

4

byte[] dataResult = cipher.doFinal(input);

Cipher.init(mode, key)方法中MODE指加密或解密模式,值为Cipher.ENCRYPT_MODE或Cipher.DECRYPT_MODE,参数key在加密时传入PublicKey,在解密时以PrivateKey传入。Cipher.doFinal(byte[] data)则是将待编码数据传入后并返回编码结果。为了将编码结果转为可读字符串,通常最后还使用BASE 64算法对最终的byte[]数据编码后显示给开发者。

Demo运行效果如下图所示:

图17-4  使用动态生成的公钥和私钥进行RSA加密

图17-5  使用预设的N、e、d值进行RSA加密

使用 mbed TLS(现称 Arm Mbed TLS)进行 RSA 加密操作时,`mbedtls_rsa_context` 结构体是核心组件之一,用于存储 RSA 密钥参数和配置信息。要获取 `mbedtls_rsa_context` 中的参数值,需要了解其内部结构和相关函数的使用方式。 ### mbedtls_rsa_context 的主要字段 `mbedtls_rsa_context` 结构体定义在 `mbedtls/rsa.h` 中,其主要字段包括: - `MBEDTLS_RSA_PUBLIC`:仅包含公钥参数(N 和 E)。 - `MBEDTLS_RSA_PRIVATE`:包含完整的密钥参数(N, E, D, P, Q 等)。 - N(mbedtls_mpi):模数(Modulus)。 - E(mbedtls_mpi):公钥指数(Public exponent)。 - D(mbedtls_mpi):私钥指数(Private exponent)。 - P、Q(mbedtls_mpi):大素数 p 和 q,满足 N = P * Q。 - DP、DQ、QP(mbedtls_mpi):用于中国剩余定理(CRT)加速解密。 - RLN(int):RSA 密钥长度(以字节为单位)。 ### 获取 RSA 参数的方法 要获取 RSA 密钥的参数值,需使用 `mbedtls_mpi_write_binary()` 函数将 `mbedtls_mpi` 类型转换为二进制形式。以下是一个示例代码,展示如何提取 RSA 密钥的各个参数: ```c #include "mbedtls/rsa.h" #include "mbedtls/mpi.h" #include <stdio.h> #include <string.h> void print_mpi(const char *name, const mbedtls_mpi *X) { size_t olen; unsigned char buf[512]; mbedtls_mpi_write_binary(X, buf, sizeof(buf)); olen = mbedtls_mpi_size(X); printf("%s (hex): ", name); for (size_t i = 0; i < olen; i++) { printf("%02X", buf[i]); } printf("\n"); } int extract_rsa_params(mbedtls_rsa_context *rsa) { if (!mbedtls_rsa_is_priv(rsa)) { printf("RSA context does not contain private key.\n"); return -1; } print_mpi("N", &rsa->N); print_mpi("E", &rsa->E); print_mpi("D", &rsa->D); print_mpi("P", &rsa->P); print_mpi("Q", &rsa->Q); print_mpi("DP", &rsa->DP); print_mpi("DQ", &rsa->DQ); print_mpi("QP", &rsa->QP); return 0; } ``` ### 配置 mbedtls_rsa_context 的方法 可以通过以下方式配置 `mbedtls_rsa_context`: - **生成密钥**:使用 `mbedtls_rsa_gen_key()` 函数生成 RSA 密钥对。 - **导入密钥**:使用 `mbedtls_rsa_import()` 或 `mbedtls_rsa_import_raw()` 导入已有的密钥参数。 - **设置填充方式**:通过 `mbedtls_rsa_set_padding()` 设置 RSA 填充方式(如 PKCS#1 v1.5 或 OAEP)。 - **设置哈希算法**:在签名或验证时指定哈希算法(如 SHA-256)。 例如,生成 RSA 密钥对: ```c mbedtls_rsa_context rsa; mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0); mbedtls_rsa_gen_key(&rsa, mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537); ``` ### 注意事项 - 在访问 `mbedtls_rsa_context` 中的参数前,必须确保密钥已经正确初始化或导入。 - 若密钥为公钥,则无法访问私钥参数(如 D、P、Q 等)[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值