encrypt-rsa

0x01 背景介绍

一般信息安全注重三个点!安全性和完整性,可靠性。 针对这几个点:目前用的比较的安全方式就是加密,签名。 如:各大公司采用的证书就是基于这几种方式。
本次主要简单讲解rsa。

0x02 RSA介绍

RSA是一种非对称密钥。被广泛用来做签名和加密。 ras长度有1024, 2048 …

0x03 RSA使用

1.利用程序直接生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package com.test.tools;

import sun.misc.BASE64Decoder;

import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

import javax.crypto.Cipher;

/**
* 非对称加密RSA
* @author bing
*/
public class RSAUtils {

/**
* 公钥加密
* @param content
* @param publicKey
* @return
* @throws Exception
*/
public static String encrypt(String data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
//加密的数据必须为字节
return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
}

/**
* 私钥解密
* @param content
* @param privateKey
* @return
* @throws Exception
*/
public static String decrypt(String data, PrivateKey privateKey) throws Exception {
byte[] bytes = Base64.getDecoder().decode(data);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher.doFinal(bytes));
}

/**
* 签名
* @param data
* @param privateKey
* @return
* @throws Exception
* @throws Exception
*/
public static String sign(String content, byte[] privateKeyBytes) throws Exception
{
//单例获取key工厂类,将拿到的privateKeyBytes创建PKCS8EncodedKeySpec对象,通过其获取PrivateKey对象
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// 用key工厂对象生成私钥
PrivateKey priKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));

//获取Signature对象,签名算法为SHA1WithRSA,此处还有较多可选择比如MD2withRSA/MD5withRSA/SHA1withRSA/SHA256withRSA等
Signature signature = Signature.getInstance("SHA1WithRSA");
//初始化签名
signature.initSign(priKey);
//签名的数据必须为字节
signature.update(content.getBytes());
byte[] encodeResult = signature.sign();
return Base64.getEncoder().encodeToString(encodeResult);
}

/**
* 验证
* @param data
* @param sign
* @param publicKey
* @return
* @throws Exception
*/
public static boolean verify(String content, String sign, byte[] publicKeyBytes) throws Exception {
byte[] bytes = Base64.getDecoder().decode(sign);
//单例获取key工厂类,将拿到的publicKey创建X509EncodedKeySpec对象,通过其获取PublicKey对象
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));

//获取Signature对象,签名算法为SHA1WithRSA,此处还有较多可选择比如MD2withRSA/MD5withRSA/SHA1withRSA/SHA256withRSA等
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(pubKey);
signature.update( content.getBytes() );
boolean bverify = signature.verify( bytes );
return bverify;
}

/**
* 生成密钥对
* @return
* @throws Exception
*/
public static KeyPair genKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
return keyPairGenerator.generateKeyPair();
}

/**
* base64 to 公钥
* @param key 密钥字符串 to publickey
* @throws Exception
*/
public static PublicKey getPublicKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = (new BASE64Decoder()).decodeBuffer(key);

X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}

public static void main(String[] args) throws Exception {

String data = "this is a securet message dfgsgdfgfgdfg";

KeyPair keyPair = genKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
byte[] publicKeyBytes = publicKey.getEncoded();
byte[] privateKeyBytes = privateKey.getEncoded();

// 打印rsa公私密钥的modulus和exponent
RSAPublicKey publicKeyT = (RSAPublicKey) keyPair.getPublic();
System.out.println("测试公钥 modulus:" + publicKeyT.getModulus().toString(16) ); //BigInteger to 16进制
System.out.println("测试公钥 format:" + publicKeyT.getFormat());
BigInteger modulus = publicKeyT.getModulus() ;
BigInteger publicExponent = publicKeyT.getPublicExponent();

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulus,publicExponent);
PublicKey publicKeyT2 = keyFactory.generatePublic(rsaPublicKeySpec);
byte[] test = publicKeyT2.getEncoded();
System.out.println("测试公钥:" + Base64.getEncoder().encodeToString( test ) );

// 测试公钥转换modulus和exponent
String t2 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+Aq3Pa7PFYG047xTEAcFmvgFt65FAtmFMMkgL3Gl6K+3tIviClRUlKNr5W1wvJNrzB8Z2/YD9Qebc1crmAxU4CcxRNUlSBfnlKMRTqNeB9RY1tcD0TxGU6RFC3BHKudWghF0vk9U8zCG20ax9ZtncqlzNB4GthuF2haVzJhAeGYwshcK+kdyilKfuv9AfmrOgQ9HVMIPEmlWL/rE4kfvYbBLhCI1M/PZvlHXVQKHdevJiz5+0CBjpBuOkMYyK84Vl8rieS1iL6tBcCZtzVoFoMalNePwLjk4UWY2yxwNA6k655ePijRlr1jEk1RvauCcrGFt22sfP27roMRAlA+JQIDAQAB";
RSAPublicKey t3 = (RSAPublicKey) getPublicKey(t2);
System.out.println("自定义公钥 modulus:" + t3.getModulus().toString(16) ); //BigInteger to 16进制
System.out.println("长度:" + t3.getModulus().toString(2).length() );

// 获取公,私钥,并以base64格式打印出来
// System.out.println("公钥:" + Base64.getEncoder().encodeToString( publicKeyBytes ) );
// System.out.println("私钥:" + Base64.getEncoder().encodeToString( privateKeyBytes ) );

// 公钥加密
System.out.println( "公钥的长度:" + publicKeyBytes.length );
String encryptedString = encrypt(data, publicKey);
System.out.println("加密数据:" + encryptedString);
System.out.println("加密数据长度: " + encryptedString.length() );

// 私钥解密
System.out.println( "私钥的长度:" + privateKeyBytes.length );
String decryptedString = decrypt(encryptedString, privateKey);
System.out.println("解密数据:" + decryptedString);

// 私钥签名
String sign = sign(data, privateKeyBytes);
System.out.println("签名:" + sign);
System.out.println("签名后的数据长度:" + sign.length() );

// 公钥验签
boolean flag = verify(data, sign, publicKeyBytes);
System.out.println("验证:" + flag);

}
/**
* RSA 1024最大加密明文大小 :117 - 128
*/

}

2.利用openssl命令直接生成

1
2
3
4
5
OpenSSL中RSA私钥文件生成命令为:
openssl genrsa -out private_rsa.pem 2048

生成RSA公钥命令为:
openssl rsa -in private_rsa.pem -pubout -out public_rsa.pem

3.单片机一般16进制数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
16进制密钥生成命令:
openssl rsa -in phone_rsa_private_key.pem -text -out private.txt

使用命令,可得到如下几个部分:
RSAPrivateKey ::= SEQUENCE {
version Version, //版本
modulus INTEGER, -- n //模
publicExponent INTEGER, -- e //公钥指数
privateExponent INTEGER, -- d //私钥指数
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}

公钥语法为:(n, e)
私钥语法为:(n, d)


获取密钥的模和指数:
# /usr/bin/python
# encoding: utf-8

import base64

def str2key(s):
# 对字符串解码
b_str = base64.b64decode(s)

if len(b_str) < 162:
return False

hex_str = ''

# 按位转换成16进制
for x in b_str:
h = hex(ord(x))[2:]
h = h.rjust(2, '0')
hex_str += h

# 找到模数和指数的开头结束位置
m_start = 29 * 2
e_start = 159 * 2
m_len = 128 * 2
e_len = 3 * 2

modulus = hex_str[m_start:m_start + m_len]
exponent = hex_str[e_start:e_start + e_len]

return modulus,exponent

if __name__ == "__main__":
pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21TAIfT/vexbobzH7Q8SUdP5uDPXEBKzOjx2L28y7Xs1d9v3tdPfKI2LR7PAzWBmDMn8riHrDDNpUpJnlAGUqJG9ooPn8j7YNpcxCa1iybOlc2kEhmJn5uwoanQq+CA6agNkqly2H4j6wIDAQAB"
key = str2key(pubkey)
print key


使用密钥的模和指数,生成公钥及加密
import rsa
message = 'test'
modulus = int(key[0], 16)
exponent = int(key[1], 16)
rsa_pubkey = rsa.PublicKey(modulus, exponent)
crypto = rsa.encrypt(message, rsa_pubkey)
b64str = base64.b64encode(crypto)
print b64str


第二种直接把数据的模和指数计算出来,进行格式转换。

0x04 AES加解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package test;

import java.security.Key;
import java.security.SecureRandom;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;


public class DemoAESUtil {
/**
* 加密
* @param str
* @param key
* @return
* @throws Exception
*/
public static String encrypt(String str, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, generateKey(key));
byte[] bytes = cipher.doFinal(str.getBytes());

return Base64.getEncoder().encodeToString(bytes);
}

/**
* 解密
* @param str
* @param key
* @return
* @throws Exception
*/
public static String decrypt(String str, String key) throws Exception {
byte[] bytes = Base64.getDecoder().decode(str);
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, generateKey(key));
return new String(cipher.doFinal(bytes));
}

/**
* 生成key
* @param key
* @return
* @throws Exception
*/
private static Key generateKey(String key) throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, new SecureRandom(key.getBytes())); // 密钥长度 128/192/256
return new SecretKeySpec(keyGenerator.generateKey().getEncoded(), "AES");
}

public static void main(String[] args) throws Exception {

String str = "hello world";
String key = "password";

// 加密
String encryptedString = encrypt(str, key);
System.out.println("加密后:" + encryptedString);

// 解密
String decryptedString = decrypt(encryptedString, key);
System.out.println("解密后:" + new String(decryptedString));

}

}

参考

https://github.com/ghyg525/util_java_safe
https://tools.ietf.org/html/rfc5246 –ssl
http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html

坚持原创技术分享,您的支持将鼓励我继续创作!