项目介绍
网络安全期末大作业:通过课堂上讲解的对称加密和非对称加密算法,实现一个能够加密解密的邮箱客户端。
注意:本文不介绍算法,只讲解主要实现过程。
效果展示
生成密钥
加密邮件
解密
整体设计
用 Java 实现加密邮箱客户端,由于是网络安全作业,所以主要在于加解密算法的编写。这里我采用随机生成的字符串为 AES128 的密钥,加密密文,再用其他用户的公钥采用 RSA 加密 AES128 密 钥,最后封装成 EncryptMessage 对象,向其他用户发送密钥和密文。
流程图如下:
加密邮件算法设计
加密设计
采用随机生成的字符串作为 AES128 的密钥,加密密文。
再用其他用户的公钥采用 RSA 加密 AES128 密钥。
最后封装成 EncryptMessage 对象,向其他用户发送密钥和密文。
其他设计
字符集编码:Unicodee 支持所有字符编码。
输出格式:Base64 编码。
EncryptMessage 对象:
- 密钥:RSA 加密 AES 密钥。
- 密文: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
|
public static RSAUtils.SecretKey createRSAKeyPair() { return RSAUtils.createKeyPair(); }
public static EncryptMessage encrypt(String plaintext, String publicKey) throws UnsupportedEncodingException { publicKey = new String(Base64.getDecoder().decode(publicKey)); String secretKey = getRandomString(16); String cipherText = AESUtils.encrypt(plaintext, secretKey); String key = encryptSecretKey(secretKey, publicKey); cipherText = new String(Base64.getEncoder().encode(cipherText.getBytes())); key = new String(Base64.getEncoder().encode(key.getBytes())); return new EncryptMessage(key, cipherText); }
public static String decrypt(EncryptMessage encryptMessage, String privateKey) throws UnsupportedEncodingException { privateKey = new String(Base64.getDecoder().decode(privateKey)); String cipherText = encryptMessage.getCipherText(); String key = encryptMessage.getKey(); cipherText = new String(Base64.getDecoder().decode(cipherText)); key = new String(Base64.getDecoder().decode(key)); String secretKey = decryptSecretKey(key, privateKey); return AESUtils.decrypt(cipherText, secretKey); }
|
AES 算法
- 编码方式为 Unicode,支持所有字符编码;
- 密钥:AES128;
- 加密模式:ECB;
- 填充方式:ZerosPadding。
实现步骤
加密步骤
明文、密钥按 Unicode 编码格式转字节数组;
填充明文为 16 字节的倍数,刚好为 16 字节的倍数也要填充;
明文、密钥数组转字节矩阵;
分块加密
密文字节矩阵转密文字节数组;
密文字节数组转密文字节字符串;
密文拼接。
解密步骤
- 密钥按 Unicode 编码格式转字节数组;
- 密文 16 进制字符串转字节数组;
- 密文、密钥数组转字节矩阵;
- 分块解密
- 生成拓展密钥;
- 初始变化;
- 9 轮循环;
- 最后轮循环;
- 明文字节矩阵转明文字节数组;
- 明文字节数组按 Unicode 编码方式转字符串;
- 明文拼接。
关键代码
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
|
private static byte mixMultiply(byte fixMatrix, byte content) { byte mulContent = 0; if (fixMatrix == 0x01) { return content; } else if (fixMatrix == 0x02) { mulContent = GF(content, fixMatrix); } else if (fixMatrix == 0x03) { mulContent = (byte) (GF(content, (byte) 0x02) ^ content); } else if (fixMatrix == 0x09) { mulContent = (byte) (GF(GF(GF(content, (byte) 0x02), (byte) 0x02), (byte) 0x02) ^ content); } else if (fixMatrix == 0x0B) { mulContent = (byte) ((GF(content, (byte) 0x02) ^ GF(GF(GF(content, (byte) 0x02), (byte) 0x02), (byte) 0x02)) ^ content); } else if (fixMatrix == 0x0D) { mulContent = (byte) ((GF(GF(content, (byte) 0x02), (byte) 0x02) ^ GF(GF(GF(content, (byte) 0x02), (byte) 0x02), (byte) 0x02)) ^ content); } else if (fixMatrix == 0x0E) { mulContent = (byte) (GF(content, (byte) 0x02) ^ GF(GF(content, (byte) 0x02), (byte) 0x02) ^ GF(GF(GF(content, (byte) 0x02), (byte) 0x02), (byte) 0x02)); }
return mulContent; }
private static byte GF(byte content, byte fixMatrix) { byte mulContent = 0;
if ((content & 0x80) == 0x80) { mulContent = (byte) ((byte) (content << 1) ^ 0x1B); } else { mulContent = (byte) (content << 1); }
return mulContent; }
|
RSA 算法
本文 RSA 算法的主要实现是取自 CSDN 社区的 foDask Jhonson RSA算法原理及实现(Java) 。
RSA 生成的公钥 PublicKey(e, n) 和密钥 PrivateKey(d, n) 的类型为 BigInteger;
公钥和密钥格式为两个超大整数且用 “.” 分割,最后再用 Base64 编码。
素数长度:1024 bit;
素数的准确率 1-(2 ^ (-accuracy)):128;
公钥指数 e 的取值:根据PKCS#1的建议,公钥指数e是可以选取较小的素数3或65537(=2^16+1)。这里取 65537。
实现步骤
- 选择一对不相等且足够大的质数p, q;
- 计算 p,q 的乘积 n;
- 计算 n 的欧拉函数 φ(n) = (p - 1) * (q - 1);
- 选择一个与 φ(n) 互质的整数 e(1 < e < φ(n));
- 计算出 e 对于 φ(n) 的模反元素 d;
- 计算出的 d 不能是负数,如果是负数,d = d + φ(n)。使d为正数;
- 返回计算出的密钥。
关键代码
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
|
private static BigInteger[] exGCD(BigInteger e, BigInteger PHI_n) { if (PHI_n.signum() == 0) { return new BigInteger[]{e, new BigInteger("1"), new BigInteger("0")}; } else { BigInteger[] bigIntegers = exGCD(PHI_n, e.mod(PHI_n)); BigInteger y = bigIntegers[1].subtract(e.divide(PHI_n).multiply(bigIntegers[2])); return new BigInteger[]{bigIntegers[0], bigIntegers[2], y}; } }
|
📌最后:希望本文能够给您提供帮助,文章中有不懂或不正确的地方,请在下方评论区💬留言!
🔗参考文献:
🌐 Dask Jhonson. RSA算法原理及实现(Java). [EB/OL]. (2020-05-02). [2022-12-04]. https://blog.csdn.net/qq_41115702/article/details/105884973