教学服务系统

 找回密码
 立即注册
搜索
查看: 521|回复: 5

信息计算2019级1班14号钱星一

[复制链接]

10

主题

23

帖子

114

积分

注册会员

Rank: 2

积分
114
发表于 2022-6-2 13:59:20 | 显示全部楼层 |阅读模式
本帖最后由 钱星一 于 2022-6-2 13:59 编辑

RSA签名和加密

一、Java实现RSA签名和加密
RSA属于非对称加密算法,有两个密钥。区别于共享密钥的对称加密算法,如DES和AES。公钥可以共享给任何人,私钥自己进行保管。公钥用于加密数据,使得该加密数据只能用私钥进行解密;私钥也可用于签名数据,签名和数据一起发送,然后使用公钥验证数据是否被篡改。

二、RSA实现密钥对
在实际做任何形式加密之前,需要有公钥和私钥两个密钥对。幸运的是,Java提供了非常简单的方法,首先获得RSA KeyPairGenerator实例,然后使用2048为长度进行初始化并传入SecureRandom实例。后者用作生成器的熵或随机数据源。第三行生成密钥对,所有内容都就是这样,非常简单。如果需要使用密钥对存储器,需要使用Java KeyStore工具,后面会详细解释。

三、加密和解密
这里使用base64编码,主要是典型的REST API中很常用,我们当然也可以不用base64编码而直接使用字节数组。确保明确地且一致地为字符串指定字节编码。否则字节错位将导致密文和无法解密或验证签名。首先获得RSA密码实例并设置为加密模式,然后使用公钥加密消息。然后一次性传入消息字符串的字节数组并获得加密后的字节数组,最后转码并返回。运维RSA是相当慢,比对称加密算法如AES要慢的多。

四、签名与验证
我们使用公钥进行加密,然后使用私钥解密。理论上反过来也行(私钥加密,公钥解密),但这不安全且大多数库(包括java.security)也不支持。然而,这种方式在构建API时比较有用。使用私钥对消息进行签名,然后使用公钥进行验证签名。这种机制可以确保消息确实来着公钥创建者(私钥持有者),使得传输过程消息不会被篡改。

五、运行结果



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

10

主题

23

帖子

114

积分

注册会员

Rank: 2

积分
114
 楼主| 发表于 2022-6-2 14:00:09 | 显示全部楼层
程序代码:
Base64.java
  1. package com.ihep;

  2. public final class Base64 {

  3.     static private final int     BASELENGTH           = 128;
  4.     static private final int     LOOKUPLENGTH         = 64;
  5.     static private final int     TWENTYFOURBITGROUP   = 24;
  6.     static private final int     EIGHTBIT             = 8;
  7.     static private final int     SIXTEENBIT           = 16;
  8.     static private final int     FOURBYTE             = 4;
  9.     static private final int     SIGN                 = -128;
  10.     static private final char    PAD                  = '=';
  11.     static private final boolean fDebug               = false;
  12.     static final private byte[]  base64Alphabet       = new byte[BASELENGTH];
  13.     static final private char[]  lookUpBase64Alphabet = new char[LOOKUPLENGTH];

  14.     static {
  15.         for (int i = 0; i < BASELENGTH; ++i) {
  16.             base64Alphabet[i] = -1;
  17.         }
  18.         for (int i = 'Z'; i >= 'A'; i--) {
  19.             base64Alphabet[i] = (byte) (i - 'A');
  20.         }
  21.         for (int i = 'z'; i >= 'a'; i--) {
  22.             base64Alphabet[i] = (byte) (i - 'a' + 26);
  23.         }

  24.         for (int i = '9'; i >= '0'; i--) {
  25.             base64Alphabet[i] = (byte) (i - '0' + 52);
  26.         }

  27.         base64Alphabet['+'] = 62;
  28.         base64Alphabet['/'] = 63;

  29.         for (int i = 0; i <= 25; i++) {
  30.             lookUpBase64Alphabet[i] = (char) ('A' + i);
  31.         }

  32.         for (int i = 26, j = 0; i <= 51; i++, j++) {
  33.             lookUpBase64Alphabet[i] = (char) ('a' + j);
  34.         }

  35.         for (int i = 52, j = 0; i <= 61; i++, j++) {
  36.             lookUpBase64Alphabet[i] = (char) ('0' + j);
  37.         }
  38.         lookUpBase64Alphabet[62] = (char) '+';
  39.         lookUpBase64Alphabet[63] = (char) '/';

  40.     }

  41.     private static boolean isWhiteSpace(char octect) {
  42.         return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
  43.     }

  44.     private static boolean isPad(char octect) {
  45.         return (octect == PAD);
  46.     }

  47.     private static boolean isData(char octect) {
  48.         return (octect < BASELENGTH && base64Alphabet[octect] != -1);
  49.     }

  50.     public static String encode(byte[] binaryData) {

  51.         if (binaryData == null) {
  52.             return null;
  53.         }

  54.         int lengthDataBits = binaryData.length * EIGHTBIT;
  55.         if (lengthDataBits == 0) {
  56.             return "";
  57.         }

  58.         int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
  59.         int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
  60.         int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
  61.         char encodedData[] = null;

  62.         encodedData = new char[numberQuartet * 4];

  63.         byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;

  64.         int encodedIndex = 0;
  65.         int dataIndex = 0;
  66.         if (fDebug) {
  67.             System.out.println("number of triplets = " + numberTriplets);
  68.         }

  69.         for (int i = 0; i < numberTriplets; i++) {
  70.             b1 = binaryData[dataIndex++];
  71.             b2 = binaryData[dataIndex++];
  72.             b3 = binaryData[dataIndex++];

  73.             if (fDebug) {
  74.                 System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
  75.             }

  76.             l = (byte) (b2 & 0x0f);
  77.             k = (byte) (b1 & 0x03);

  78.             byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
  79.             byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
  80.             byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);

  81.             if (fDebug) {
  82.                 System.out.println("val2 = " + val2);
  83.                 System.out.println("k4   = " + (k << 4));
  84.                 System.out.println("vak  = " + (val2 | (k << 4)));
  85.             }

  86.             encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
  87.             encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
  88.             encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
  89.             encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
  90.         }

  91.         // form integral number of 6-bit groups
  92.         if (fewerThan24bits == EIGHTBIT) {
  93.             b1 = binaryData[dataIndex];
  94.             k = (byte) (b1 & 0x03);
  95.             if (fDebug) {
  96.                 System.out.println("b1=" + b1);
  97.                 System.out.println("b1<<2 = " + (b1 >> 2));
  98.             }
  99.             byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
  100.             encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
  101.             encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
  102.             encodedData[encodedIndex++] = PAD;
  103.             encodedData[encodedIndex++] = PAD;
  104.         } else if (fewerThan24bits == SIXTEENBIT) {
  105.             b1 = binaryData[dataIndex];
  106.             b2 = binaryData[dataIndex + 1];
  107.             l = (byte) (b2 & 0x0f);
  108.             k = (byte) (b1 & 0x03);

  109.             byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
  110.             byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);

  111.             encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
  112.             encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
  113.             encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
  114.             encodedData[encodedIndex++] = PAD;
  115.         }

  116.         return new String(encodedData);
  117.     }

  118.     public static byte[] decode(String encoded) {

  119.         if (encoded == null) {
  120.             return null;
  121.         }

  122.         char[] base64Data = encoded.toCharArray();
  123.         // remove white spaces
  124.         int len = removeWhiteSpace(base64Data);

  125.         if (len % FOURBYTE != 0) {
  126.             return null;//should be divisible by four
  127.         }

  128.         int numberQuadruple = (len / FOURBYTE);

  129.         if (numberQuadruple == 0) {
  130.             return new byte[0];
  131.         }

  132.         byte decodedData[] = null;
  133.         byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
  134.         char d1 = 0, d2 = 0, d3 = 0, d4 = 0;

  135.         int i = 0;
  136.         int encodedIndex = 0;
  137.         int dataIndex = 0;
  138.         decodedData = new byte[(numberQuadruple) * 3];

  139.         for (; i < numberQuadruple - 1; i++) {

  140.             if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
  141.                     || !isData((d3 = base64Data[dataIndex++]))
  142.                     || !isData((d4 = base64Data[dataIndex++]))) {
  143.                 return null;
  144.             }//if found "no data" just return null

  145.             b1 = base64Alphabet[d1];
  146.             b2 = base64Alphabet[d2];
  147.             b3 = base64Alphabet[d3];
  148.             b4 = base64Alphabet[d4];

  149.             decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
  150.             decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
  151.             decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
  152.         }

  153.         if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {
  154.             return null;//if found "no data" just return null
  155.         }

  156.         b1 = base64Alphabet[d1];
  157.         b2 = base64Alphabet[d2];

  158.         d3 = base64Data[dataIndex++];
  159.         d4 = base64Data[dataIndex++];
  160.         if (!isData((d3)) || !isData((d4))) {//Check if they are PAD characters
  161.             if (isPad(d3) && isPad(d4)) {
  162.                 if ((b2 & 0xf) != 0)//last 4 bits should be zero
  163.                 {
  164.                     return null;
  165.                 }
  166.                 byte[] tmp = new byte[i * 3 + 1];
  167.                 System.arraycopy(decodedData, 0, tmp, 0, i * 3);
  168.                 tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
  169.                 return tmp;
  170.             } else if (!isPad(d3) && isPad(d4)) {
  171.                 b3 = base64Alphabet[d3];
  172.                 if ((b3 & 0x3) != 0)//last 2 bits should be zero
  173.                 {
  174.                     return null;
  175.                 }
  176.                 byte[] tmp = new byte[i * 3 + 2];
  177.                 System.arraycopy(decodedData, 0, tmp, 0, i * 3);
  178.                 tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
  179.                 tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
  180.                 return tmp;
  181.             } else {
  182.                 return null;
  183.             }
  184.         } else { //No PAD e.g 3cQl
  185.             b3 = base64Alphabet[d3];
  186.             b4 = base64Alphabet[d4];
  187.             decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
  188.             decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
  189.             decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);

  190.         }

  191.         return decodedData;
  192.     }

  193.     private static int removeWhiteSpace(char[] data) {
  194.         if (data == null) {
  195.             return 0;
  196.         }

  197.         // count characters that's not whitespace
  198.         int newSize = 0;
  199.         int len = data.length;
  200.         for (int i = 0; i < len; i++) {
  201.             if (!isWhiteSpace(data[i])) {
  202.                 data[newSize++] = data[i];
  203.             }
  204.         }
  205.         return newSize;
  206.     }
  207. }
复制代码
回复

使用道具 举报

10

主题

23

帖子

114

积分

注册会员

Rank: 2

积分
114
 楼主| 发表于 2022-6-2 14:01:58 | 显示全部楼层
maintest.java
  1. package com.ihep;

  2. public class MainTest {

  3.     public static void main(String[] args) throws Exception {
  4.         String filepath = "E:/tmp/";

  5.         // 生成公钥和私钥文件
  6.         RSAEncrypt.genKeyPair(filepath);

  7.         System.out.println("--------------公钥加密私钥解密过程-------------------");
  8.         String plainText = "钊钊致命";
  9.         // 公钥加密过程,得到加密后的数据
  10.         byte[] cipherData = RSAEncrypt.encrypt(RSAEncrypt.loadPublicKeyByStr(RSAEncrypt.loadPublicKeyByFile(filepath)), plainText.getBytes());
  11.         // 对加密数据进行编码处理,得到加密后的字符串
  12.         String cipher = Base64.encode(cipherData);
  13.         // 私钥解密过程
  14.         byte[] res = RSAEncrypt.decrypt(RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadPrivateKeyByFile(filepath)), Base64.decode(cipher));
  15.         String restr = new String(res);
  16.         System.out.println("原文:" + plainText);
  17.         System.out.println("加密:" + cipher);
  18.         System.out.println("解密:" + restr);
  19.         System.out.println();

  20.         System.out.println("--------------私钥加密公钥解密过程-------------------");
  21.         plainText = "钊钊致命";
  22.         //私钥加密过程
  23.         cipherData = RSAEncrypt.encrypt(RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadPrivateKeyByFile(filepath)), plainText.getBytes());
  24.         cipher = Base64.encode(cipherData);
  25.         //公钥解密过程
  26.         res = RSAEncrypt.decrypt(RSAEncrypt.loadPublicKeyByStr(RSAEncrypt.loadPublicKeyByFile(filepath)), Base64.decode(cipher));
  27.         restr = new String(res);
  28.         System.out.println("原文:" + plainText);
  29.         System.out.println("加密:" + cipher);
  30.         System.out.println("解密:" + restr);
  31.         System.out.println();

  32.         System.out.println("---------------私钥签名过程------------------");
  33.         String content = "我想喝奶盖";
  34.         String signstr = RSASignature.sign(content, RSAEncrypt.loadPrivateKeyByFile(filepath));
  35.         System.out.println("签名原串:" + content);
  36.         System.out.println("签名串:" + signstr);
  37.         System.out.println();

  38.         System.out.println("---------------公钥校验签名------------------");
  39.         System.out.println("签名原串:" + content);
  40.         System.out.println("签名串:" + signstr);

  41.         System.out.println("验签结果:" + RSASignature.doCheck(content, signstr, RSAEncrypt.loadPublicKeyByFile(filepath)));
  42.         System.out.println();

  43.     }
  44. }
复制代码


回复

使用道具 举报

10

主题

23

帖子

114

积分

注册会员

Rank: 2

积分
114
 楼主| 发表于 2022-6-2 14:03:26 | 显示全部楼层
RSAEncrypt.java
  1. package com.ihep;

  2. import javax.crypto.BadPaddingException;
  3. import javax.crypto.Cipher;
  4. import javax.crypto.IllegalBlockSizeException;
  5. import javax.crypto.NoSuchPaddingException;
  6. import java.io.*;
  7. import java.security.*;
  8. import java.security.interfaces.RSAPrivateKey;
  9. import java.security.interfaces.RSAPublicKey;
  10. import java.security.spec.InvalidKeySpecException;
  11. import java.security.spec.PKCS8EncodedKeySpec;
  12. import java.security.spec.X509EncodedKeySpec;
  13. private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6',
  14. '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
  15. public static void genKeyPair(String filePath) {
  16. // 密钥对生成器
  17. KeyPairGenerator keyPairGen = null;
  18. try {
  19. // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
  20. keyPairGen = KeyPairGenerator.getInstance("RSA");
  21. } catch (NoSuchAlgorithmException e) {
  22. // TODO Auto-generated catch block
  23. e.printStackTrace();
  24. }
  25. // 初始化密钥对生成器,密钥大小为96-1024位
  26. keyPairGen.initialize(1024, new SecureRandom());
  27. // 生成一个密钥对,保存在keyPair中
  28. KeyPair keyPair = keyPairGen.generateKeyPair();
  29. // 得到私钥
  30. RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
  31. // 得到公钥
  32. RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
  33. try {
  34. // 得到公钥字符串
  35. String publicKeyString = Base64.encode(publicKey.getEncoded());
  36. // 得到私钥字符串
  37. String privateKeyString = Base64.encode(privateKey.getEncoded());
  38. // 将密钥对写入到文件
  39. FileWriter pubfw = new FileWriter(filePath + "/publicKey.keystore");
  40. FileWriter prifw = new FileWriter(filePath + "/privateKey.keystore");
  41. BufferedWriter pubbw = new BufferedWriter(pubfw);
  42. BufferedWriter pribw = new BufferedWriter(prifw);
  43. pubbw.write(publicKeyString);
  44. pribw.write(privateKeyString);
  45. pubbw.flush();
  46. pubbw.close();
  47. pubfw.close();
  48. pribw.flush();
  49. pribw.close();
  50. prifw.close();
  51. } catch (Exception e) {
  52. e.printStackTrace();
  53. }
  54. }
  55. public static String loadPublicKeyByFile(String path) throws Exception {
  56. try {
  57. BufferedReader br = new BufferedReader(new FileReader(path
  58. + "/publicKey.keystore"));
  59. String readLine = null;
  60. StringBuilder sb = new StringBuilder();
  61. while ((readLine = br.readLine()) != null) {
  62. sb.append(readLine);
  63. }
  64. br.close();
  65. return sb.toString();
  66. } catch (IOException e) {
  67. throw new Exception("公钥数据流读取错误");
  68. } catch (NullPointerException e) {
  69. throw new Exception("公钥输入流为空");
  70. }
  71. }
  72. public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr)
  73. throws Exception {
  74. try {
  75. byte[] buffer = Base64.decode(publicKeyStr);
  76. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  77. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
  78. return (RSAPublicKey) keyFactory.generatePublic(keySpec);
  79. } catch (NoSuchAlgorithmException e) {
  80. throw new Exception("无此算法");
  81. } catch (InvalidKeySpecException e) {
  82. throw new Exception("公钥非法");
  83. } catch (NullPointerException e) {
  84. throw new Exception("公钥数据为空");
  85. }
  86. }
  87. public static String loadPrivateKeyByFile(String path) throws Exception {
  88. try {
  89. BufferedReader br = new BufferedReader(new FileReader(path
  90. + "/privateKey.keystore"));
  91. String readLine = null;
  92. StringBuilder sb = new StringBuilder();
  93. while ((readLine = br.readLine()) != null) {
  94. sb.append(readLine);
  95. }
  96. br.close();
  97. /** 该字符串从私钥文件中获取,称之为私钥字符串
  98. * MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALaIDyyav7J8oD/8sONfP772aa1foDlHmoXRArqe+2po14c1q7nGR8DLk
  99. * 55J0sgxt/EOvtvxtwo4cPFtoLSBzdKVn/ZmR7uyHQXsMzqcmz7n7DGAzNNqxlu0SLHVjZ4HscWxnC+dGa037Ec9m5DKRT6aMckNmxZp3G
  100. * xic9wzId6zAgMBAAECgYEAhpOUFH/XvEH0aJjm1gzA1AubaI8rc2/edrDeQTe8B/1agr7IaMTO3E97++VT+fPmOV10zHbPTELGysnYBZ3
  101. * 6X/wLaKs+GMO/uewNAsyu46u3izwNVCygBiM62mlmhk3Y9J8ZcmoQHzXGV0p0TuGJsIlAofCAN1ielWLPcEVUPckCQQDoQm4GKe2C26oU
  102. * aXRwLy2WLczfmqLTlJ8QyJs8ruL78JikhDgLWaLPBJ+lHmTxahC4HjJ9LhNxNVcpbyMiHhM1AkEAyTBjkOGwBJTlYMmS1hn6BoqA5xCRF
  103. * Iv8gZZMxj+xcvSSEfZU9ObVArOBQRUoIO3GdsyaVfG/DNwuP7zGI16/RwJBAMfyIEu4HpsvxeyKmE3Xn5QQ27WHpzMkWAeX22RTXl7r0k
  104. * yW8rR6txkm7tS0JMxbtgb7IBX564zjEaU+4u0FHR0CQG+v+zYM9Ag3GHd4r5lH5nMHJLQhkEjVxaGy7IAKD9p/Ry/NjjA+jPXo7NJSimp
  105. * tVYXR48PeZm8fNFWR2HT+PjUCQFu3yN71iiXA0EW35Y1HHIE814gUV/O5T4gpUNzK9NLvHLFQNbzgoZER5yIGgBWDju1keBkojm8P69A7
  106. * qdtXILU=
  107. */
  108. return sb.toString();
  109. } catch (IOException e) {
  110. throw new Exception("私钥数据读取错误");
  111. } catch (NullPointerException e) {
  112. throw new Exception("私钥输入流为空");
  113. }
  114. }
  115. public static RSAPrivateKey loadPrivateKeyByStr(String privateKeyStr)
  116. throws Exception {
  117. try {
  118. byte[] buffer = Base64.decode(privateKeyStr);
  119. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
  120. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  121. return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
  122. } catch (NoSuchAlgorithmException e) {
  123. throw new Exception("无此算法");
  124. } catch (InvalidKeySpecException e) {
  125. throw new Exception("私钥非法");
  126. } catch (NullPointerException e) {
  127. throw new Exception("私钥数据为空");
  128. }
  129. }
  130. public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData)
  131. throws Exception {
  132. if (publicKey == null) {
  133. throw new Exception("加密公钥为空, 请设置");
  134. }
  135. Cipher cipher = null;
  136. try {
  137. // 使用默认RSA
  138. cipher = Cipher.getInstance("RSA");
  139. // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
  140. // 初始化算法:公钥加密
  141. cipher.init(Cipher.ENCRYPT_MODE, publicKey);
  142. // 公钥加密后的字节数组
  143. byte[] output = cipher.doFinal(plainTextData);
  144. return output;
  145. } catch (NoSuchAlgorithmException e) {
  146. throw new Exception("无此加密算法");
  147. } catch (NoSuchPaddingException e) {
  148. e.printStackTrace();
  149. return null;
  150. } catch (InvalidKeyException e) {
  151. throw new Exception("加密公钥非法,请检查");
  152. } catch (IllegalBlockSizeException e) {
  153. throw new Exception("明文长度非法");
  154. } catch (BadPaddingException e) {
  155. throw new Exception("明文数据已损坏");
  156. }
  157. }

  158. public static byte[] encrypt(RSAPrivateKey privateKey, byte[] plainTextData)
  159. throws Exception {
  160. if (privateKey == null) {
  161. throw new Exception("加密私钥为空, 请设置");
  162. }
  163. Cipher cipher = null;
  164. try {
  165. // 使用默认RSA
  166. cipher = Cipher.getInstance("RSA");
  167. // 初始化算法:私钥加密
  168. cipher.init(Cipher.ENCRYPT_MODE, privateKey);
  169. // 加密后的密文数据,以字符数组的形式存在
  170. byte[] output = cipher.doFinal(plainTextData);
  171. return output;
  172. } catch (NoSuchAlgorithmException e) {
  173. throw new Exception("无此加密算法");
  174. } catch (NoSuchPaddingException e) {
  175. e.printStackTrace();
  176. return null;
  177. } catch (InvalidKeyException e) {
  178. throw new Exception("加密私钥非法,请检查");
  179. } catch (IllegalBlockSizeException e) {
  180. throw new Exception("明文长度非法");
  181. } catch (BadPaddingException e) {
  182. throw new Exception("明文数据已损坏");
  183. }
  184. }

  185. public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData)
  186. throws Exception {
  187. if (privateKey == null) {
  188. throw new Exception("解密私钥为空, 请设置");
  189. }
  190. Cipher cipher = null;
  191. try {
  192. // 使用默认RSA
  193. cipher = Cipher.getInstance("RSA");
  194. // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
  195. // 初始化解密算法:私钥解密
  196. cipher.init(Cipher.DECRYPT_MODE, privateKey);
  197. // 解密,生成以字符数组形式存在的明文数据
  198. byte[] output = cipher.doFinal(cipherData);
  199. return output;
  200. } catch (NoSuchAlgorithmException e) {
  201. throw new Exception("无此解密算法");
  202. } catch (NoSuchPaddingException e) {
  203. e.printStackTrace();
  204. return null;
  205. } catch (InvalidKeyException e) {
  206. throw new Exception("解密私钥非法,请检查");
  207. } catch (IllegalBlockSizeException e) {
  208. throw new Exception("密文长度非法");
  209. } catch (BadPaddingException e) {
  210. throw new Exception("密文数据已损坏");
  211. }
  212. }
  213. public static byte[] decrypt(RSAPublicKey publicKey, byte[] cipherData)
  214. throws Exception {
  215. if (publicKey == null) {
  216. throw new Exception("解密公钥为空, 请设置");
  217. }
  218. Cipher cipher = null;
  219. try {
  220. // 使用默认RSA
  221. cipher = Cipher.getInstance("RSA");
  222. // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
  223. // 初始化加密算法:公钥解密
  224. cipher.init(Cipher.DECRYPT_MODE, publicKey);
  225. byte[] output = cipher.doFinal(cipherData);
  226. // 以字符数组形式存在的明文数据
  227. return output;
  228. } catch (NoSuchAlgorithmException e) {
  229. throw new Exception("无此解密算法");
  230. } catch (NoSuchPaddingException e) {
  231. e.printStackTrace();
  232. return null;
  233. } catch (InvalidKeyException e) {
  234. throw new Exception("解密公钥非法,请检查");
  235. } catch (IllegalBlockSizeException e) {
  236. throw new Exception("密文长度非法");
  237. } catch (BadPaddingException e) {
  238. throw new Exception("密文数据已损坏");
  239. }
  240. }
  241. public static String byteArrayToString(byte[] data) {
  242. StringBuilder stringBuilder = new StringBuilder();
  243. for (int i = 0; i < data.length; i++) {
  244. // 取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
  245. stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);
  246. // 取出字节的低四位 作为索引得到相应的十六进制标识符
  247. stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
  248. if (i < data.length - 1) {
  249. stringBuilder.append(' ');
  250. }
  251. }
  252. return stringBuilder.toString();
  253. }
  254. }
复制代码


回复

使用道具 举报

10

主题

23

帖子

114

积分

注册会员

Rank: 2

积分
114
 楼主| 发表于 2022-6-2 14:04:05 | 显示全部楼层
RSASignature.java
  1. package com.ihep;

  2. import java.security.KeyFactory;
  3. import java.security.PrivateKey;
  4. import java.security.PublicKey;
  5. import java.security.spec.PKCS8EncodedKeySpec;
  6. import java.security.spec.X509EncodedKeySpec;

  7. /**
  8. * RSA签名验签类
  9. */
  10. public class RSASignature {

  11.     /**
  12.      * 签名算法
  13.      */
  14.     public static final String SIGN_ALGORITHMS = "SHA1WithRSA";

  15.     public static String sign(String content, String privateKey, String encode) {
  16.         try {
  17.             PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey));

  18.             KeyFactory keyf = KeyFactory.getInstance("RSA");
  19.             PrivateKey priKey = keyf.generatePrivate(priPKCS8);

  20.             java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);

  21.             signature.initSign(priKey);
  22.             signature.update(content.getBytes(encode));

  23.             byte[] signed = signature.sign();

  24.             return Base64.encode(signed);
  25.         } catch (Exception e) {
  26.             e.printStackTrace();
  27.         }

  28.         return null;
  29.     }

  30.     public static String sign(String content, String privateKey) {
  31.         try {
  32.             PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey));
  33.             KeyFactory keyf = KeyFactory.getInstance("RSA");
  34.             PrivateKey priKey = keyf.generatePrivate(priPKCS8);
  35.             // 这里签名使用的是 SHA1WithRSA
  36.             java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
  37.             // 以私钥字符串初始化签名
  38.             signature.initSign(priKey);
  39.             // 将原始串注入签名中
  40.             signature.update(content.getBytes());
  41.             // 签名后的结果,以字符数组形式存在
  42.             byte[] signed = signature.sign();
  43.             // 签名后的结果,以base64编码形式存在
  44.             return Base64.encode(signed);
  45.         } catch (Exception e) {
  46.             e.printStackTrace();
  47.         }
  48.         return null;
  49.     }

  50.     public static boolean doCheck(String content, String sign, String publicKey, String encode) {
  51.         try {
  52.             KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  53.             byte[] encodedKey = Base64.decode(publicKey);
  54.             PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));


  55.             java.security.Signature signature = java.security.Signature
  56.                     .getInstance(SIGN_ALGORITHMS);

  57.             signature.initVerify(pubKey);
  58.             signature.update(content.getBytes(encode));

  59.             boolean bverify = signature.verify(Base64.decode(sign));
  60.             return bverify;

  61.         } catch (Exception e) {
  62.             e.printStackTrace();
  63.         }

  64.         return false;
  65.     }

  66.     public static boolean doCheck(String content, String sign, String publicKey) {
  67.         try {
  68.             KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  69.             byte[] encodedKey = Base64.decode(publicKey);
  70.             PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
  71.             // 使用 SHA1WithRSA 签名算法
  72.             java.security.Signature signature = java.security.Signature
  73.                     .getInstance(SIGN_ALGORITHMS);
  74.             // 用公钥初始化签名校验
  75.             signature.initVerify(pubKey);
  76.             // 原始串注入签名校验中
  77.             signature.update(content.getBytes());
  78.             // 验证签名结果
  79.             boolean bverify = signature.verify(Base64.decode(sign));
  80.             // 返回签名是否成功
  81.             return bverify;
  82.         } catch (Exception e) {
  83.             e.printStackTrace();
  84.         }
  85.         return false;
  86.     }
  87. }
复制代码


回复

使用道具 举报

10

主题

23

帖子

114

积分

注册会员

Rank: 2

积分
114
 楼主| 发表于 2022-6-2 14:08:45 | 显示全部楼层
椭圆曲线加密算法(ECC)
一、算法介绍
椭圆曲线密码体制来源于对椭圆曲线的研究,所谓椭圆曲线指的是由韦尔斯特拉斯(Weierstrass)方程:y2+a1xy+a3y=x3+a2x2+a4x+a6 (1)
所确定的平面曲线。其中系数ai(I=1,2,…,6)定义在某个域上,可以是有理数域、实数域、复数域,还可以是有限域GF(pr),椭圆曲线密码体制中用到的椭圆曲线都是定义在有限域上的。椭圆曲线上所有的点外加一个叫做无穷远点的特殊点构成的集合连同一个定义的加法运算构成一个Abel群。在等式
mP=P+P+…+P=Q (2)中,已知m和点P求点Q比较容易,反之已知点Q和点P求m却是相当困难的,这个问题称为椭圆曲线上点群的离散对数问题。椭圆曲线密码体制正是利用这个困难问题设计而来。公钥算法是基于数学函数(如单向陷门函数),公钥密码体制根据其所依据的难题一般分为三类:大整数分解问题类、离散对数问题类、椭圆曲线类。本文是在素域Zp上的,以Menezes-Vanstone形式的椭圆加密算法。
二、算法原理
在素域上的曲线函数为:y^2 = x ^ 3 +a*  x+ b, 其中a,b为小于p的非负数,且 4*a^3+ 27*b^2 != 0
对于在素域上的加法中,对于所有的点P,Q 属于E(Zp),有加法规则:
1。P + O = O + P = P ,P + (-P) = O;  O为椭圆曲线上的零点或者称为无限远的点,但是O在椭圆曲线的加法域上。
2.加法的分配率和结合律,对于s,t 属于Zp,有(s + t )* P = s * P + t* P;
3.对于 P = (x1,y1),Q = (x2,y2) ,并且 P != - Q,则P + Q=(x3,y3),
x3 = k^2 - x1 -x2;
y3 = k*(x1-x3) - y1;
k = (y2-y1)/(x2-x1)   if P != Q;
k = (3x1^2 + a)/(2*y1) if P == Q;
椭圆曲线在素域上的运算用到除法,而在除法的规则是a / b = c mod p 即计算 a x b^-1 = c mod p ,其中 b^-1为b的乘法逆元, 即 b x b^-1 = 1 mod p。对于乘法逆元,当b与p互素时,存在唯一解,而这里p是一个素数,且b不可能为1,则肯定有解。对于求乘法逆元,一般使用欧几里德算法,如下:
  1. int getX_1(int x,int mod){
  2.         int Q,X1,X2,X3,Y1,Y2,Y3,T1,T2,T3;
  3.         X1 = 1;
  4.         X2 = 0;
  5.         X3 = mod;
  6.         Y1 = 0;
  7.         Y2 = 1;
  8.         Y3 = (x%mod + mod) %mod;//获得正整数
  9.         while(Y3 != 1){
  10.                 Q = X3 / Y3;
  11.                 T1 = X1 - Q * Y1;
  12.                 T2 = X2 - Q * Y2;
  13.                 T3 = X3 - Q * Y3;
  14.                 X1 = Y1;
  15.                 X2 = Y2;
  16.                 X3 = Y3;
  17.                 Y1 = T1;
  18.                 Y2 = T2;
  19.                 Y3 = T3;
  20.         }
  21.         return Y2;
  22. }
复制代码
乘法运算规则:
1. 对于任意 k 属于 Zp,有 k * P = P + ..... + P (k个P相加)
2. 对于任意 s,t 属于 Zp,有 s *(t *P) = (s*t)*P
对于Menezes-Vanstone的椭圆加密算法:
1. 产生密钥,
任选一个整数k ,0<k<p ,为私钥,在曲线上任选一点 A ,并计算 B = k*A ,公钥为(A,,B)。其中又可称A为基钥,对于最小整数n以使 n* A = O ,则n称为周期,要是周期为素数,且为一个较大值才合理。
2.加密过程:
令明文为 M = (m1,m2),M可以不是曲线E上的点。计算得到密文(C1,C2),其中任选一个数属于Zp:
C1 = r * A;;
Y= (y1,y2) = r * B;
C2 = (C21,C22) = (y1 * m1 mod p,y2* m2 mod p)
3 解密过程;
计算Z = (z1,z2) = k*C1;计算明文 M = (C21 * z1^-1 mod p, C22 * z2 ^ -1 mod p).
c++中的模运算,当有负数存在时无法达到正确结果,简直是坑,如 -1 % 2,在使用vs2012进行测试,会返回-1,而不是1. c++中模运算结果的符号和被除数的符号一致。
参数选取:选取 p = 127,曲线函数为: y^2 = x^3 + 5* x + 37, a = 5 ,b= 37, r = 7.选取私钥 k = 9选取一个点A为(11,4)则 B = k*A = (120,41)
三、源代码
  1. #include "stdafx.h"
  2. #include <string>
  3. #include <iostream>
  4. using namespace std;
  5. const int k = 9;
  6. const int a = 5;
  7. const int b = 37;
  8. const int p = 127;
  9. const int r =7;

  10. int getX_1(int x,int mod){
  11.         int Q,X1,X2,X3,Y1,Y2,Y3,T1,T2,T3;
  12.         X1 = 1;
  13.         X2 = 0;
  14.         X3 = mod;
  15.         Y1 = 0;
  16.         Y2 = 1;
  17.         Y3 = (x%mod + mod) %mod;//获得正整数
  18.         while(Y3 != 1){
  19.                 Q = X3 / Y3;
  20.                 T1 = X1 - Q * Y1;
  21.                 T2 = X2 - Q * Y2;
  22.                 T3 = X3 - Q * Y3;
  23.                 X1 = Y1;
  24.                 X2 = Y2;
  25.                 X3 = Y3;
  26.                 Y1 = T1;
  27.                 Y2 = T2;
  28.                 Y3 = T3;
  29.         }
  30.         return Y2;
  31. }//获得其乘法逆元

  32. struct point{
  33.         int x;
  34.         int y;
  35. };
  36. point A,B;//公钥
  37. typedef pair<point,point> twopoint;
  38. bool operator == (point pa,point pb){
  39.         return pa.x == pb.x && pa.y == pb.y;
  40. }
  41. point operator + (point pa , point pb){
  42.         int k;
  43.         
  44.         if(pa == pb)
  45.                 k = ((3 * pa.x * pa.x + a) * getX_1(2* pa.y ,p)) % p ;
  46.         else
  47.                 k = (pb.y - pa.y) * getX_1(pb.x - pa.x , p) %p;
  48.                 point c;
  49.                 c.x = (k*k - pa.x -pb.x) %p;
  50.                 c.y = (k * (pa.x - c.x) - pa.y)%p ;
  51.                 c.x = (c.x + p) %p;
  52.                 c.y = (c.y + p) %p;
  53.                
  54.                 return c;
  55. }
  56. point operator * (point &b,int n){
  57.                 point q = b;
  58.                 n = n -1;
  59.                 for(int i = 1 ; i < n;i++){
  60.                         q = q + b ;
  61.                 }
  62.                 return q;
  63. }
  64. twopoint ECodePoint(point m){
  65.         point c1,c2;
  66.         c1 = A * r ;
  67.         point Y = B * r ;
  68.         c2.x = Y.x * m.x % p ;
  69.         c2.y = Y.y * m.y % p ;
  70.         return twopoint(c1,c2);
  71. }
  72. point DCodePoint(twopoint t){
  73.         point Z = t.first * k;
  74.         point m;
  75.         m.x = t.second.x * getX_1(Z.x,p) % p ;
  76.         m.y = t.second.y * getX_1(Z.y,p) % p ;
  77.         return m;
  78. }
  79. string ECode(string input){
  80.         string output = "";
  81.         point M;
  82.         twopoint C;
  83.         for(int i =0; i < input.length();i++){
  84.                 M.x = i;
  85.                 M.y = input[i];
  86.                 C = ECodePoint(M);
  87.                 output += (char)C.first.x ;
  88.                 output += (char)C.first.y ;
  89.                 output += (char)C.second.x ;
  90.                 output += (char)C.second.y ;
  91.         }
  92.         return output;
  93. }
  94. string DCode(string input){
  95.         string output = "";
  96.         point M;
  97.         twopoint C;
  98.         if(input.length()%4 != 0)
  99.                 return "错误输入";
  100.         for(int i = 0;i < input.length();){
  101.                 C.first.x = input[i++];
  102.                 C.first.y = input[i++];
  103.                 C.second.x = input[i++];
  104.                 C.second.y = input[i++];
  105.                 M = DCodePoint(C);
  106.                 output += (char)M.y;
  107.         }
  108.         return output;
  109. }
  110. int main()
  111. {
  112.         A.x = 11;
  113.         A.y = 4;
  114.         B = A*k;
  115.         string s = "";
  116.         cout<<"使用在素域上的曲线 y^2 = x^3 + 5*x +37   ,使用Menezes-Vanstone的算法:"<<endl;
  117.         cout<<"在素域p=127上,私钥为k=9,公钥A(11,4),B(120,41),对明文字符串直接转换为int进行加密"<<endl;
  118.         cout<<"请输入要加密的内容:"<<endl;
  119.         cin>>s;
  120.         cout<<"密文如下:"<<"\r\n";
  121.         s = ECode(s);
  122.         cout<<s<<endl;
  123.         cout<<"对之前密文解密,得到明文如下(由于输入密文不正确绝对会使这个程序出错,所以只能解密绝对安全的密文):"<<"\r\n";
  124.         s = DCode(s);
  125.         cout<<s<<"\r\n"<<"完成"<<endl;
  126.         cin>>s;
  127.         return 0;
  128. }
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

教学服务系统

GMT+8, 2025-4-30 07:29 , Processed in 0.021149 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表