├── FifthUnit ├── RSA.java └── RSAs.java ├── FirstUnit ├── Pairkey.java ├── Vigenere.java └── VigenereClient.java ├── FourthUnit └── SHA.java ├── Practice ├── RC4.java └── Rc.java ├── README.md ├── SixthUnit ├── DoubleAnd.java ├── ECIES.java ├── ElGamal.java └── Shanks.java └── ThirdUnit ├── AES.java ├── DES.java └── DESECB.java /FifthUnit/RSA.java: -------------------------------------------------------------------------------- 1 | package FifthUnit; 2 | 3 | import java.math.BigInteger; 4 | import java.util.Random; 5 | 6 | public class RSA { 7 | private static BigInteger n; // large prime 8 | private static BigInteger e; // public key 9 | private static BigInteger b; // private key 10 | private static BigInteger p; // prime 11 | private static BigInteger q; // prime 12 | 13 | public static void main(String[] args) { 14 | String x = "The quick brown fox jumps over the lazy dog"; 15 | RSA rsa = new RSA(); 16 | String ciphertext = rsa.operation(x, "encrypt"); 17 | //System.out.println( 18 | // "\npublic key:" + "(" + n + "," + b + ")" + "\n" + "private key:" + "(" + p + "," + q + "," + a + ")"); 19 | //System.out.println("plaintext:" + x + "\n" + "ciphertext:" + ciphertext); 20 | } 21 | 22 | // RSA encryption 23 | public String operation(String x, String model) { 24 | String ciphertext = new String(); 25 | 26 | //get n,a,b 27 | giveKey(); 28 | 29 | // encrypt or decrypt 30 | if (model.equals("encrypt")) { 31 | 32 | } else if (model.equals("decrypt")) { 33 | 34 | } else { 35 | System.out.println("You have gave a wrong model !"); 36 | } 37 | 38 | return ciphertext; 39 | } 40 | 41 | // give public key and private key 42 | public void giveKey() { 43 | //get n,a,b,p,q 44 | producePQ(); 45 | n = p.multiply(q); 46 | BigInteger eulerN = p.subtract(new BigInteger("1")).multiply(q.subtract(new BigInteger("1"))); 47 | randomB(eulerN); 48 | inverseB(b); 49 | } 50 | 51 | // large prime generation 52 | public void producePQ() { 53 | while (true) { 54 | // produce p and q randomly 55 | p = BigInteger.probablePrime(32, new Random()); 56 | q = BigInteger.probablePrime(32, new Random()); 57 | while (p.equals(q)) { 58 | p = BigInteger.probablePrime(32, new Random()); 59 | q = BigInteger.probablePrime(32, new Random()); 60 | } 61 | System.out.println("p:" + p + "\n" + "q:" + q); 62 | } 63 | 64 | } 65 | 66 | // produce a random 67 | public void randomB(BigInteger eulerN) { 68 | } 69 | 70 | // calculate the multiplicative inverse 71 | public void inverseB(BigInteger b) { 72 | } 73 | 74 | // square and multiply 75 | public BigInteger squareMultiply(BigInteger x, BigInteger c, BigInteger n) { 76 | BigInteger z = new BigInteger(""); 77 | return z; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /FifthUnit/RSAs.java: -------------------------------------------------------------------------------- 1 | package FifthUnit; 2 | 3 | import java.math.BigInteger; 4 | import java.util.Random; 5 | 6 | public class RSAs { 7 | private static BigInteger n; // large prime 8 | private static BigInteger e; // public key 9 | private static BigInteger b; // private key 10 | private static BigInteger p; // prime 11 | private static BigInteger q; // prime 12 | 13 | public static void main(String[] args) { 14 | String plaintext = "The quick brown fox jumps over the lazy dog"; 15 | RSAs rsas = new RSAs(); 16 | rsas.giveKey(); 17 | BigInteger[] encrypt = rsas.encrypt(plaintext); 18 | String decrypt = rsas.decrypt(encrypt); 19 | System.out.println("\nplaintext:" + plaintext + "\n\nencrpyt:"); 20 | for (int i = 0; i < encrypt.length; ++i) { 21 | System.out.println(encrypt[i]); 22 | } 23 | System.out.println("\ndecrypt:" + decrypt); 24 | } 25 | 26 | // RSA encryption 27 | public BigInteger[] encrypt(String plaintext) { 28 | BigInteger[] encrypt = new BigInteger[plaintext.length()]; 29 | BigInteger m, c; 30 | for (int i = 0; i < plaintext.length(); ++i) { 31 | m = BigInteger.valueOf(plaintext.charAt(i)); 32 | c = m.modPow(e, n); 33 | encrypt[i] = c; 34 | } 35 | return encrypt; 36 | } 37 | 38 | // RSA decryption 39 | public String decrypt(BigInteger[] encrypt) { 40 | StringBuffer plaintext = new StringBuffer(); 41 | BigInteger m, c; 42 | for (int i = 0; i < encrypt.length; ++i) { 43 | c = encrypt[i]; 44 | m = c.modPow(b, n); 45 | plaintext.append((char) m.intValue()); 46 | } 47 | return plaintext.toString(); 48 | } 49 | 50 | // give public key and private key 51 | public void giveKey() { 52 | // get p,q,n,e,b 53 | producePQ(); 54 | n = p.multiply(q); 55 | BigInteger eulerN = p.subtract(new BigInteger("1")).multiply(q.subtract(new BigInteger("1"))); 56 | produceEB(eulerN); 57 | System.out.println("n:" + n + "\np:" + p + "\nq:" + q + "\ne:" + e + "\nb:" + b); 58 | } 59 | 60 | // large prime p and q generation 61 | public void producePQ() { 62 | p = BigInteger.probablePrime(32, new Random()); 63 | q = BigInteger.probablePrime(32, new Random()); 64 | while (p.equals(q)) { 65 | p = BigInteger.probablePrime(32, new Random()); 66 | q = BigInteger.probablePrime(32, new Random()); 67 | } 68 | } 69 | 70 | // produce public key e,private key b 71 | public void produceEB(BigInteger eulerN) { 72 | e = BigInteger.probablePrime((int) (Math.random() * 63 + 2), new Random()); 73 | while (e.compareTo(eulerN) != -1 | eulerN.divide(e).equals(new BigInteger("0"))) { 74 | e = BigInteger.probablePrime((int) (Math.random() * 63 + 2), new Random()); 75 | } 76 | //e = BigInteger.valueOf(65537); 77 | b = e.modInverse(eulerN); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /FirstUnit/Pairkey.java: -------------------------------------------------------------------------------- 1 | package FirstUnit; 2 | 3 | public class Pairkey { 4 | public static void main(String[] args) { 5 | Pairkey pairkey = new Pairkey(); 6 | pairkey.calculation(); 7 | } // main--end 8 | 9 | public void calculation() { 10 | int total1 = 0; // 密钥总数 11 | int total2 = 0; 12 | 13 | // 当detK=1时计算对合密钥 14 | System.out.println("当detK=1时,对合密钥为:"); 15 | for (int i = 0; i < 26; ++i) { // k11和k22 16 | for (int j = 0; j < 26; ++j) { // k12 17 | for (int k = 0; k < 26; ++k) { // k21 18 | if ((mod26(i * i - j * k) == 1) && (j == mod26(-j) && (k == mod26(-k)))) { 19 | System.out.print(i + " " + j + " " + k + " " + i + " "); 20 | ++total1; 21 | } 22 | } // for--end 23 | } 24 | } 25 | System.out.println("对合密钥数为:" + total1); 26 | 27 | // 当detK=-1时计算对合密钥 28 | System.out.println("\n当detK=-1时,对合密钥为:"); 29 | for (int i = 0; i < 26; ++i) { // k11 30 | for (int j = 0; j < 26; ++j) { // k12 31 | for (int k = 0; k < 26; ++k) { // k21 32 | for (int l = 0; l < 26; ++l) { // k22 33 | if ((mod26(i * l - j * k) == 25) && (i == mod26(-l)) && (l == mod26(-i))) { 34 | System.out.print(i + " " + j + " " + k + " " + l + " "); 35 | ++total2; 36 | } 37 | } 38 | } 39 | } 40 | } 41 | System.out.println("密钥数为:" + total2); 42 | System.out.println("\n密钥总数为:" + (total1 + total2)); 43 | } 44 | 45 | public int mod26(int number) { 46 | while (number < 0) { 47 | number += 26; 48 | } 49 | return number % 26; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /FirstUnit/Vigenere.java: -------------------------------------------------------------------------------- 1 | package FirstUnit; 2 | 3 | import java.util.*; 4 | 5 | public class Vigenere { 6 | public static void main(String[] args) { 7 | String ciphertext = "KCCPKBGUFDPHQTYAVINRRTMVGRKDNBVFDETDGILTXRGUDDKOTFMBPVGEGLTGCKQRACQCWDNAWCRXIZAKFTLEWRPTYCQKYVXCHKFTPONCQQRHJVAJUWETMCMSPKQDYHJVDAHCTRLSVSKCGCZQQDZXGSFRLSWCWSJTBHAFSIASPRJAHKJRJUMVGKMITZHFPDISPZLVLGWTFPLKKEBDPGCEBSHCTJRWXBAFSPEZQNRWXCVYCGAONWDDKACKAWBBIKFTIOVKCGGHJVLNHIFFSQESVYCLACNVRWBBIREPBBVFEXOSCDYGZWPFDTKFQIYCWHJVLNHIQIBTKHJVNPIST"; 8 | Vigenere vigenere = new Vigenere(); 9 | vigenere.decryptCipher(vigenere.Friedman(ciphertext), ciphertext); 10 | } 11 | 12 | // Friedman测试法确定密钥长度 13 | public int Friedman(String ciphertext) { 14 | int keyLength = 1; // 猜测密钥长度 15 | double[] Ic; // 重合指数 16 | double avgIc; // 平均重合指数 17 | ArrayList cipherGroup; // 密文分组 18 | 19 | while (true) { 20 | Ic = new double[keyLength]; 21 | cipherGroup = new ArrayList<>(); 22 | avgIc = 0; 23 | 24 | // 1 先根据密钥长度分组 25 | for (int i = 0; i < keyLength; ++i) { 26 | StringBuilder tempGroup = new StringBuilder(); 27 | for (int j = 0; i + j * keyLength < ciphertext.length(); ++j) { 28 | tempGroup.append(ciphertext.charAt(i + j * keyLength)); 29 | } 30 | cipherGroup.add(tempGroup.toString()); 31 | } 32 | 33 | // 2 再计算每一组的重合指数 34 | for (int i = 0; i < keyLength; ++i) { 35 | String subCipher = cipherGroup.get(i); // 子串 36 | HashMap occurrenceNumber = new HashMap<>(); // 字母及其出现的次数 37 | 38 | // 2.1 初始化字母及其次数键值对 39 | for (int h = 0; h < 26; ++h) { 40 | occurrenceNumber.put((char) (h + 65), 0); 41 | } 42 | 43 | // 2.2 统计每个字母出现的次数 44 | for (int j = 0; j < subCipher.length(); ++j) { 45 | occurrenceNumber.put(subCipher.charAt(j), occurrenceNumber.get(subCipher.charAt(j)) + 1); 46 | } 47 | 48 | // 2.3 计算重合指数 49 | double denominator = Math.pow((double) subCipher.length(), 2); 50 | for (int k = 0; k < 26; ++k) { 51 | double o = (double) occurrenceNumber.get((char) (k + 65)); 52 | Ic[i] += o * (o - 1); 53 | } 54 | Ic[i] /= denominator; 55 | } 56 | 57 | // 3 判断退出条件,重合指数的平均值是否大于0.065 58 | for (int i = 0; i < keyLength; ++i) { 59 | avgIc += Ic[i]; 60 | } 61 | avgIc /= (double) keyLength; 62 | if (avgIc >= 0.06) { 63 | break; 64 | } else { 65 | keyLength++; 66 | } 67 | } // while--end 68 | 69 | // 打印密钥长度,分组,重合指数,平均重合指数 70 | System.out.println("密钥长度为:" + String.valueOf(keyLength)); 71 | System.out.println("\n密文分组及其重合指数为:"); 72 | 73 | for (int i = 0; i < keyLength; ++i) { 74 | System.out.println(cipherGroup.get(i) + " 重合指数: " + Ic[i]); 75 | } 76 | System.out.println("\n平均重合指数为: " + String.valueOf(avgIc)); 77 | 78 | return keyLength; 79 | }// Friedman--end 80 | 81 | // 再次使用重合指数法确定密钥 82 | public void decryptCipher(int keyLength, String ciphertext) { 83 | int[] key = new int[keyLength]; 84 | ArrayList cipherGroup = new ArrayList<>(); 85 | double[] probability = new double[]{0.082, 0.015, 0.028, 0.043, 0.127, 0.022, 0.02, 0.061, 0.07, 0.002, 0.008, 86 | 0.04, 0.024, 0.067, 0.075, 0.019, 0.001, 0.06, 0.063, 0.091, 0.028, 0.01, 0.023, 0.001, 0.02, 0.001}; 87 | 88 | // 1 先根据密钥长度分组 89 | for (int i = 0; i < keyLength; ++i) { 90 | StringBuilder temporaryGroup = new StringBuilder(); 91 | for (int j = 0; i + j * keyLength < ciphertext.length(); ++j) { 92 | temporaryGroup.append(ciphertext.charAt(i + j * keyLength)); 93 | } 94 | cipherGroup.add(temporaryGroup.toString()); 95 | } 96 | 97 | // 2 确定密钥 98 | for (int i = 0; i < keyLength; ++i) { 99 | double MG; // 重合指数 100 | int flag; // 移动位置 101 | int g = 0; // 密文移动g个位置 102 | HashMap occurrenceNumber; // 字母出现次数 103 | String subCipher; // 子串 104 | 105 | while (true) { 106 | MG = 0; 107 | flag = 65 + g; 108 | subCipher = cipherGroup.get(i); 109 | occurrenceNumber = new HashMap<>(); 110 | 111 | // 2.1 初始化字母及其次数 112 | for (int h = 0; h < 26; ++h) { 113 | occurrenceNumber.put((char) (h + 65), 0); 114 | } 115 | 116 | // 2.2 统计字母出现次数 117 | for (int j = 0; j < subCipher.length(); ++j) { 118 | occurrenceNumber.put(subCipher.charAt(j), occurrenceNumber.get(subCipher.charAt(j)) + 1); 119 | } 120 | 121 | // 2.3 计算重合指数 122 | for (int k = 0; k < 26; ++k, ++flag) { 123 | double p = probability[k]; 124 | flag = (flag == 91) ? 65 : flag; 125 | double f = (double) occurrenceNumber.get((char) flag) / subCipher.length(); 126 | MG += p * f; 127 | } 128 | 129 | // 2.4 判断退出条件 130 | if (MG >= 0.055) { 131 | key[i] = g; 132 | break; 133 | } else { 134 | ++g; 135 | } 136 | } // while--end 137 | } // for--end 138 | 139 | // 3 打印密钥 140 | StringBuilder keyString = new StringBuilder(); 141 | for (int i = 0; i < keyLength; ++i) { 142 | keyString.append((char) (key[i] + 65)); 143 | } 144 | System.out.println("\n密钥为: " + keyString.toString()); 145 | 146 | // 4 解密 147 | StringBuilder plainBuffer = new StringBuilder(); 148 | for (int i = 0; i < ciphertext.length(); ++i) { 149 | int keyFlag = i % keyLength; 150 | int change = (int) ciphertext.charAt(i) - 65 - key[keyFlag]; 151 | char plainLetter = (char) ((change < 0 ? (change + 26) : change) + 65); 152 | plainBuffer.append(plainLetter); 153 | } 154 | System.out.println("\n明文为:\n" + plainBuffer.toString().toLowerCase()); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /FirstUnit/VigenereClient.java: -------------------------------------------------------------------------------- 1 | package FirstUnit; 2 | 3 | import java.awt.*; 4 | import java.awt.event.*; 5 | import java.util.*; 6 | import javax.swing.*; 7 | 8 | public class VigenereClient { 9 | private JButton decodeButton; 10 | private JButton encodeButton; 11 | private JTextArea ciphertextArea; 12 | private JTextArea plaintextArea; 13 | private JTextField keyField; 14 | private String ciphertext; 15 | 16 | private int keyLength; // 密钥长度 17 | private ArrayList cipherGroup; // 密文的分组 18 | 19 | public static void main(String[] args) { 20 | VigenereClient vigenere = new VigenereClient(); 21 | } 22 | 23 | VigenereClient() { 24 | // 1 初始化框架 25 | JFrame frame = new JFrame(); 26 | frame.setSize(Toolkit.getDefaultToolkit().getScreenSize().width / 2, 27 | Toolkit.getDefaultToolkit().getScreenSize().height / 2); 28 | frame.setLocationByPlatform(true); 29 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 30 | frame.setTitle("维吉尼亚密文解密和加密"); 31 | 32 | // 2.1 密文区 33 | ciphertextArea = new JTextArea(8, 70); 34 | JScrollPane ciphertextScrollPane = new JScrollPane(ciphertextArea); 35 | ciphertextArea.setLineWrap(true); 36 | ciphertextScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 37 | ciphertextScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 38 | // 2.2 明文区 39 | plaintextArea = new JTextArea(8, 70); 40 | JScrollPane plaintextScrollPane = new JScrollPane(plaintextArea); 41 | plaintextArea.setLineWrap(true); 42 | plaintextScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 43 | plaintextScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 44 | // 2.3 把密文区和明文区加入Panel 45 | JPanel textPanel = new JPanel(); 46 | textPanel.setLayout(new BoxLayout(textPanel, BoxLayout.Y_AXIS)); 47 | textPanel.add(new JLabel("密文")); 48 | textPanel.add(ciphertextScrollPane); 49 | textPanel.add(new JLabel("明文")); 50 | textPanel.add(plaintextScrollPane); 51 | 52 | // 3.1 解密按钮 53 | decodeButton = new JButton("解密"); 54 | // 3.2 加密按钮 55 | encodeButton = new JButton("加密"); 56 | // 3.3 密钥输入框 57 | JPanel keyPanel = new JPanel(); 58 | keyField = new JTextField(10); 59 | JLabel keyJLabel = new JLabel("密钥"); 60 | keyPanel.add(keyJLabel); 61 | keyPanel.add(keyField); 62 | // 3.4 加入Panel 63 | JPanel buttonPanel = new JPanel(); 64 | buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS)); 65 | buttonPanel.add(decodeButton); 66 | buttonPanel.add(encodeButton); 67 | buttonPanel.add(keyPanel); 68 | 69 | // 4 把组件加入框架 70 | frame.getContentPane().add(BorderLayout.WEST, textPanel); 71 | frame.getContentPane().add(BorderLayout.EAST, buttonPanel); 72 | frame.setVisible(true); 73 | 74 | // 5.1 解密按钮注册事件 75 | ciphertextArea.setText( 76 | "KCCPKBGUFDPHQTYAVINRRTMVGRKDNBVFDETDGILTXRGUDDKOTFMBPVGEGLTGCKQRACQCWDNAWCRXIZAKFTLEWRPTYCQKYVXCHKFTPONCQQRHJVAJUWETMCMSPKQDYHJVDAHCTRLSVSKCGCZQQDZXGSFRLSWCWSJTBHAFSIASPRJAHKJRJUMVGKMITZHFPDISPZLVLGWTFPLKKEBDPGCEBSHCTJRWXBAFSPEZQNRWXCVYCGAONWDDKACKAWBBIKFTIOVKCGGHJVLNHIFFSQESVYCLACNVRWBBIREPBBVFEXOSCDYGZWPFDTKFQIYCWHJVLNHIQIBTKHJVNPIST"); 77 | decodeButton.addActionListener(new ActionListener() { 78 | public void actionPerformed(ActionEvent e) { 79 | if (ciphertextArea.getText() != null) { 80 | ciphertext = ciphertextArea.getText(); 81 | Friedman(); 82 | decodeCipher(); 83 | } 84 | } 85 | }); 86 | // 5.2 加密按钮注册事件 87 | encodeButton.addActionListener(new ActionListener() { 88 | public void actionPerformed(ActionEvent e) { 89 | if (keyField.getText() != null && plaintextArea.getText() != null) { 90 | encodePlain(keyField.getText(), plaintextArea.getText()); 91 | } 92 | } 93 | }); 94 | } 95 | 96 | // Friedman测试法确定密钥长度 97 | public void Friedman() { 98 | keyLength = 1; // 密钥长度 99 | double[] IC; // 重合指数 100 | double average; // 平均重合指数 101 | 102 | while (true) { 103 | IC = new double[keyLength]; 104 | cipherGroup = new ArrayList(); 105 | average = 0; 106 | 107 | // 1 先根据密钥长度分组 108 | for (int i = 0; i < keyLength; ++i) { 109 | StringBuffer temporaryGroup = new StringBuffer(); 110 | for (int j = 0; i + j * keyLength < ciphertext.length(); ++j) { 111 | temporaryGroup.append(ciphertext.charAt(i + j * keyLength)); 112 | } 113 | cipherGroup.add(temporaryGroup.toString()); 114 | } 115 | 116 | // 2 再计算每一组的重合指数 117 | for (int i = 0; i < keyLength; ++i) { 118 | String subCipher = new String(cipherGroup.get(i)); // 子串 119 | HashMap occurrenceNumber = new HashMap(); // 字母及其出现的次数 120 | 121 | // 2.1 初始化字母及其次数键值对 122 | for (int h = 0; h < 26; ++h) { 123 | occurrenceNumber.put((char) (h + 65), 0); 124 | } 125 | 126 | // 2.2 统计每个字母出现的次数 127 | for (int j = 0; j < subCipher.length(); ++j) { 128 | occurrenceNumber.put(subCipher.charAt(j), occurrenceNumber.get(subCipher.charAt(j)) + 1); 129 | } 130 | 131 | // 2.3 计算重合指数 132 | double denominator = Math.pow((double) subCipher.length(), 2); 133 | for (int k = 0; k < 26; ++k) { 134 | double o = (double) occurrenceNumber.get((char) (k + 65)); 135 | IC[i] += o * (o - 1); 136 | } 137 | IC[i] /= denominator; 138 | } 139 | 140 | // 3 判断退出条件,重合指数的平均值是否大于0.065 141 | for (int i = 0; i < keyLength; ++i) { 142 | average += IC[i]; 143 | } 144 | average /= (double) keyLength; 145 | if (average >= 0.06) { 146 | break; 147 | } else { 148 | keyLength++; 149 | } 150 | } // while--end 151 | 152 | // 打印密钥长度,分组,重合指数,平均重合指数 153 | plaintextArea.append("密钥长度为:"); 154 | plaintextArea.append(String.valueOf(keyLength) + "\n\n密文分组及其重合指数为:"); 155 | for (int i = 0; i < keyLength; ++i) { 156 | plaintextArea.append("\n" + cipherGroup.get(i) + " 重合指数: " + IC[i]); 157 | } 158 | plaintextArea.append("\n\n平均重合指数为: " + String.valueOf(average)); 159 | }// Friedman--end 160 | 161 | // 再次使用重合指数法确定密钥 162 | public void decodeCipher() { 163 | 164 | int[] key = new int[keyLength]; 165 | double[] probability = new double[]{0.082, 0.015, 0.028, 0.043, 0.127, 0.022, 0.02, 0.061, 0.07, 0.002, 0.008, 166 | 0.04, 0.024, 0.067, 0.075, 0.019, 0.001, 0.06, 0.063, 0.091, 0.028, 0.01, 0.023, 0.001, 0.02, 0.001}; 167 | 168 | // 1 确定密钥 169 | for (int i = 0; i < keyLength; ++i) { 170 | double MG; // 重合指数 171 | int flag; // 移动位置 172 | int g = 0; // 密文移动g个位置 173 | HashMap occurrenceNumber; // 字母出现次数 174 | String subCipher; // 子串 175 | 176 | while (true) { 177 | MG = 0; 178 | flag = 65 + g; 179 | subCipher = new String(cipherGroup.get(i)); 180 | occurrenceNumber = new HashMap(); 181 | 182 | // 1.1 初始化字母及其次数 183 | for (int h = 0; h < 26; ++h) { 184 | occurrenceNumber.put((char) (h + 65), 0); 185 | } 186 | 187 | // 1.2 统计字母出现次数 188 | for (int j = 0; j < subCipher.length(); ++j) { 189 | occurrenceNumber.put(subCipher.charAt(j), occurrenceNumber.get(subCipher.charAt(j)) + 1); 190 | } 191 | 192 | // 1.3 计算重合指数 193 | for (int k = 0; k < 26; ++k, ++flag) { 194 | double p = probability[k]; 195 | flag = (flag == 91) ? 65 : flag; 196 | double f = (double) occurrenceNumber.get((char) flag) / subCipher.length(); 197 | MG += p * f; 198 | } 199 | 200 | // 1.4 判断退出条件 201 | if (MG >= 0.055) { 202 | key[i] = g; 203 | break; 204 | } else { 205 | ++g; 206 | } 207 | } // while--end 208 | } // for--end 209 | 210 | // 2 打印密钥 211 | StringBuffer keyString = new StringBuffer(); 212 | for (int i = 0; i < keyLength; ++i) { 213 | keyString.append((char) (key[i] + 65)); 214 | } 215 | plaintextArea.append("\n\n密钥为: " + keyString.toString()); 216 | 217 | // 3 解密 218 | StringBuffer plainBuffer = new StringBuffer(); 219 | for (int i = 0; i < ciphertext.length(); ++i) { 220 | int keyFlag = i % keyLength; 221 | int change = (int) ciphertext.charAt(i) - 65 - key[keyFlag]; 222 | char plainLetter = (char) ((change < 0 ? (change + 26) : change) + 65); 223 | plainBuffer.append(plainLetter); 224 | } 225 | plaintextArea.append("\n\n明文为:\n" + plainBuffer.toString().toLowerCase()); 226 | } 227 | 228 | // 明文加密 229 | public void encodePlain(String key, String plaintext) { 230 | String plaintextUpper = plaintext.toUpperCase(); // 把明文转为大写 231 | String keyUpper = key.toUpperCase(); // 把密钥转为大写 232 | StringBuffer plainToCipher = new StringBuffer(); // 存储密文 233 | int[] move = new int[key.length()]; // 明文移动的位数 234 | 235 | // 1 把密钥改为移动的位数 236 | for (int i = 0; i < keyUpper.length(); ++i) { 237 | move[i] = (int) keyUpper.charAt(i) - 65; 238 | } 239 | 240 | // 2 明文加密 241 | for (int i = 0; i < plaintext.length(); ++i) { 242 | int letter = (int) plaintextUpper.charAt(i) + move[i % keyUpper.length()]; 243 | letter = letter > 91 ? (letter - 26) : letter; 244 | char cipherLetter = (char) (letter); 245 | plainToCipher.append(cipherLetter); 246 | } 247 | 248 | ciphertextArea.append(plainToCipher.toString()); 249 | } 250 | } -------------------------------------------------------------------------------- /FourthUnit/SHA.java: -------------------------------------------------------------------------------- 1 | package FourthUnit; 2 | 3 | public class SHA { 4 | public static void main(String[] args) { 5 | String x1 = ""; 6 | String x2 = "The quick brown fox jumps over the lazy dog"; 7 | SHA sha = new SHA(); 8 | String hexDigest1 = sha.encrypt(x1); 9 | String hexDigest2 = sha.encrypt(x2); 10 | System.out.println("empty:" + hexDigest1 + "\nstring:" + hexDigest2); 11 | } 12 | 13 | // padding 14 | public StringBuffer PAD(String x) { 15 | int ml; // message length 16 | StringBuffer mbStr = new StringBuffer(); // message convert to binary string 17 | for (int i = 0; i < x.length(); ++i) { 18 | StringBuffer temp = new StringBuffer(Long.toBinaryString(x.charAt(i))); // word binary string 19 | while (temp.length() < 8) { 20 | temp.insert(0, 0); 21 | } 22 | mbStr.append(temp); 23 | } 24 | ml = mbStr.length(); 25 | 26 | //calculate the d 27 | int d = 447 - ml; // the number of zeros to complement the message 28 | while (d < 0) { 29 | d += 512; 30 | } 31 | 32 | //complement the message length to 64 bits 33 | StringBuffer l = new StringBuffer(Long.toBinaryString(ml)); 34 | while (l.length() < 64) { 35 | l.insert(0, 0); 36 | } 37 | 38 | //padding mbStr 39 | mbStr.append(1); 40 | for (int i = 0; i < d; ++i) { 41 | mbStr.append(0); 42 | } 43 | mbStr.append(l); 44 | return mbStr; 45 | } 46 | 47 | //loop left shift 48 | public StringBuffer ROTL(StringBuffer temp, int s) { 49 | while (temp.length() < 32) { 50 | temp.insert(0, 0); 51 | } 52 | 53 | //loop left shift 54 | for (int i = 0; i < s; ++i) { 55 | temp.append(temp.charAt(0)); 56 | temp.deleteCharAt(0); 57 | } 58 | return temp; 59 | } 60 | 61 | // SHA-1 62 | public String encrypt(String x) { 63 | long h0 = 0x67452301L; 64 | long h1 = 0xEFCDAB89L; 65 | long h2 = 0x98BADCFEL; 66 | long h3 = 0x10325476L; 67 | long h4 = 0xC3D2E1F0L; 68 | 69 | //SHA-1-PAD 70 | StringBuffer mbStr = PAD(x); 71 | 72 | //group mbStr by 512 bits 73 | int groupNum = mbStr.length() / 512; 74 | StringBuffer[] mbStrGroup = new StringBuffer[groupNum]; 75 | for (int i = 0; i < groupNum; ++i) { 76 | mbStrGroup[i] = new StringBuffer(mbStr.substring(i * 512, (i + 1) * 512)); 77 | } 78 | 79 | //calculate message digest 80 | for (int i = 0; i < groupNum; ++i) { 81 | StringBuffer[] w = new StringBuffer[80]; 82 | 83 | //initialize ABCDE 84 | long a = h0; 85 | long b = h1; 86 | long c = h2; 87 | long d = h3; 88 | long e = h4; 89 | 90 | //initialize w0 to w15 91 | for (int j = 0; j < 16; ++j) { 92 | w[j] = new StringBuffer(mbStrGroup[i].substring(j * 32, (j + 1) * 32)); 93 | } 94 | 95 | //initialize w16 to w79 96 | for (int j = 16; j < 80; ++j) { 97 | w[j] = ROTL(new StringBuffer(Long 98 | .toBinaryString(Long.parseLong(w[j - 3].toString(), 2) ^ Long.parseLong(w[j - 8].toString(), 2) 99 | ^ Long.parseLong(w[j - 14].toString(), 2) ^ Long.parseLong(w[j - 16].toString(), 2))), 100 | 1); 101 | } 102 | 103 | //loop 0 to 79 104 | long mod = (long) Math.pow(2, 32); 105 | for (int j = 0; j < 80; ++j) { 106 | Long f, k; 107 | if (j >= 0 && j <= 19) { 108 | f = (b & c) | ((~b) & d); 109 | k = 0x5A827999L; 110 | } else if (j >= 20 && j <= 39) { 111 | f = b ^ c ^ d; 112 | k = 0x6ED9EBA1L; 113 | 114 | } else if (j >= 40 && j <= 59) { 115 | f = (b & c) | (b & d) | (c & d); 116 | k = 0x8F1BBCDCL; 117 | } else { 118 | f = b ^ c ^ d; 119 | k = 0xCA62C1D6L; 120 | } 121 | long temp = (Long.parseLong(ROTL(new StringBuffer(Long.toBinaryString(a)), 5).toString(), 2) + f + e 122 | + Long.parseLong(w[j].toString(), 2) + k) % mod; 123 | e = d; 124 | d = c; 125 | c = Long.parseLong(ROTL(new StringBuffer(Long.toBinaryString(b)), 30).toString(), 2); 126 | b = a; 127 | a = temp; 128 | } 129 | h0 = (h0 + a) % mod; 130 | h1 = (h1 + b) % mod; 131 | h2 = (h2 + c) % mod; 132 | h3 = (h3 + d) % mod; 133 | h4 = (h4 + e) % mod; 134 | } 135 | return Long.toHexString(h0) + Long.toHexString(h1) + Long.toHexString(h2) + Long.toHexString(h3) 136 | + Long.toHexString(h4); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /Practice/RC4.java: -------------------------------------------------------------------------------- 1 | package Practice; 2 | 3 | public class RC4 { 4 | 5 | public static void main(String[] args) { 6 | RC4 rc4 = new RC4(); 7 | 8 | String plaintext = "helloworld"; 9 | String key = "key"; 10 | 11 | String ciphertext = rc4.encrypt(plaintext, key); 12 | String decryptText = rc4.encrypt(ciphertext, key); 13 | 14 | System.out.print( 15 | "明文为:" + plaintext + "\n" + "密钥为:" + key + "\n\n" + "密文为:" + ciphertext + "\n" + "解密为:" + decryptText); 16 | } 17 | 18 | // 1 加密 19 | public String encrypt(final String plaintext, final String key) { 20 | Integer[] S = new Integer[256]; // S盒 21 | Character[] keySchedul = new Character[plaintext.length()]; // 生成的密钥流 22 | StringBuffer ciphertext = new StringBuffer(); 23 | 24 | ksa(S, key); 25 | rpga(S, keySchedul, plaintext.length()); 26 | 27 | for (int i = 0; i < plaintext.length(); ++i) { 28 | ciphertext.append((char) (plaintext.charAt(i) ^ keySchedul[i])); 29 | } 30 | 31 | return ciphertext.toString(); 32 | } 33 | 34 | // 1.1 KSA--密钥调度算法--利用key来对S盒做一个置换,也就是对S盒重新排列 35 | public void ksa(Integer[] s, String key) { 36 | for (int i = 0; i < 256; ++i) { 37 | s[i] = i; 38 | } 39 | 40 | int j = 0; 41 | for (int i = 0; i < 256; ++i) { 42 | j = (j + s[i] + key.charAt(i % key.length())) % 256; 43 | swap(s, i, j); 44 | } 45 | } 46 | 47 | // 1.2 RPGA--伪随机生成算法--利用上面重新排列的S盒来产生任意长度的密钥流 48 | public void rpga(Integer[] s, Character[] keySchedul, int plaintextLength) { 49 | int i = 0, j = 0; 50 | for (int k = 0; k < plaintextLength; ++k) { 51 | i = (i + 1) % 256; 52 | j = (j + s[i]) % 256; 53 | swap(s, i, j); 54 | keySchedul[k] = (char) (s[(s[i] + s[j]) % 256]).intValue(); 55 | } 56 | } 57 | 58 | // 1.3 置换 59 | public void swap(Integer[] s, int i, int j) { 60 | Integer mTemp = s[i]; 61 | s[i] = s[j]; 62 | s[j] = mTemp; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Practice/Rc.java: -------------------------------------------------------------------------------- 1 | package Practice; 2 | 3 | public class Rc { 4 | 5 | public static void main(String[] args) { 6 | String inputStr = "helloworld"; 7 | String key = "key"; 8 | 9 | String str = HloveyRC4(inputStr, key); 10 | 11 | // 打印加密后的字符串 12 | System.out.println(str); 13 | 14 | // 打印解密后的字符串 15 | System.out.println(HloveyRC4(str, key)); 16 | } 17 | 18 | public static String HloveyRC4(String aInput, String aKey) { 19 | int[] iS = new int[256]; 20 | byte[] iK = new byte[256]; 21 | 22 | for (int i = 0; i < 256; i++) 23 | iS[i] = i; 24 | 25 | int j = 1; 26 | 27 | for (short i = 0; i < 256; i++) { 28 | iK[i] = (byte) aKey.charAt((i % aKey.length())); 29 | } 30 | 31 | j = 0; 32 | 33 | for (int i = 0; i < 255; i++) { 34 | j = (j + iS[i] + iK[i]) % 256; 35 | int temp = iS[i]; 36 | iS[i] = iS[j]; 37 | iS[j] = temp; 38 | } 39 | 40 | int i = 0; 41 | j = 0; 42 | char[] iInputChar = aInput.toCharArray(); 43 | char[] iOutputChar = new char[iInputChar.length]; 44 | for (short x = 0; x < iInputChar.length; x++) { 45 | i = (i + 1) % 256; 46 | j = (j + iS[i]) % 256; 47 | int temp = iS[i]; 48 | iS[i] = iS[j]; 49 | iS[j] = temp; 50 | int t = (iS[i] + (iS[j] % 256)) % 256; 51 | int iY = iS[t]; 52 | char iCY = (char) iY; 53 | iOutputChar[x] = (char) (iInputChar[x] ^ iCY); 54 | } 55 | 56 | return new String(iOutputChar); 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cryptography 2 | 《密码学原理与实践》冯登国第三版——Java实现 3 | -------------------------------------------------------------------------------- /SixthUnit/DoubleAnd.java: -------------------------------------------------------------------------------- 1 | package sixthUnit; 2 | 3 | public class DoubleAnd { 4 | private int p; 5 | private int a; 6 | 7 | public static void main(String[] args) { 8 | DoubleAnd doubleAnd = new DoubleAnd(127, 1); 9 | 10 | doubleAnd.operation(new int[] { 2, 6 }, new int[] { 1, 0, -1, 0, -1, 0, 0, -1 }); 11 | } 12 | 13 | public DoubleAnd(int p, int a) { 14 | this.p = p; 15 | this.a = a; 16 | } 17 | 18 | public int[] operation(int[] P, int[] c) { 19 | int[] Q = new int[] { 0, 0 }; 20 | for (int i = 0; i < c.length; ++i) { 21 | Q = add(Q, Q); 22 | if (c[i] == 1) { 23 | Q = add(Q, P); 24 | } else if (c[i] == -1) { 25 | int[] PT = new int[2]; 26 | PT[0] = P[0]; 27 | PT[1] = p - P[1]; 28 | Q = add(Q, PT); 29 | } 30 | System.out.println(Q[0] + " " + Q[1]); 31 | } 32 | return Q; 33 | } 34 | 35 | public int[] add(int[] P, int[] Q) { 36 | int[] R = new int[2]; 37 | 38 | if (P[0] == 0 && P[1] == 0) { 39 | R[0] = Q[0]; 40 | R[1] = Q[1]; 41 | return R; 42 | } else if (Q[0] == 0 && Q[1] == 0) { 43 | R[0] = P[0]; 44 | R[1] = P[1]; 45 | return R; 46 | } else if (P[0] == Q[0] && P[1] == -Q[1]) { 47 | System.out.println("相加为无穷远点"); 48 | } else { 49 | int lambda; 50 | if (P[0] == Q[0] && P[1] == Q[1]) { 51 | lambda = Euclidean(p, (2 * P[1]) % p); 52 | lambda = lambda * (3 * P[0] * P[0] + a) % p; 53 | } else { 54 | lambda = Euclidean(p, (Q[0] - P[0] + p) % p); 55 | lambda = (lambda * (Q[1] - P[1] + p)) % p; 56 | } 57 | R[0] = (lambda * lambda - P[0] - Q[0]) % p; 58 | R[1] = (lambda * (P[0] - R[0]) - P[1]) % p; 59 | while (R[0] < 0) { 60 | R[0] += p; 61 | } 62 | while (R[1] < 0) { 63 | R[1] += p; 64 | } 65 | } 66 | return R; 67 | } 68 | 69 | public int Euclidean(int a, int b) { 70 | int a0 = a; 71 | int b0 = b; 72 | int t0 = 0; 73 | int t = 1; 74 | int q = (int) Math.floor((double) a0 / b0); 75 | int r = a0 - q * b0; 76 | while (r > 0) { 77 | int temp = (t0 - q * t) % a; 78 | t0 = t; 79 | t = temp; 80 | a0 = b0; 81 | b0 = r; 82 | q = (int) Math.floor((double) a0 / b0); 83 | r = a0 - q * b0; 84 | } 85 | if (b0 != 1) { 86 | System.out.println("没有逆元!"); 87 | } 88 | while (t < 0) { 89 | t += a; 90 | } 91 | return t; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /SixthUnit/ECIES.java: -------------------------------------------------------------------------------- 1 | package sixthUnit; 2 | 3 | public class ECIES { 4 | private int a; // 多项式参数 5 | private int b; // 多项式参数 6 | private int p; // 模数 7 | private int m; // 密钥 8 | private int[] P; // 循环子群 9 | 10 | public static void main(String[] args) { 11 | ECIES ecies = new ECIES(1, 6, 11, new int[] { 2, 7 }, 7); 12 | ecies.encrypt(9); 13 | ecies.decrypt(new int[] { 7, 1 }, 6); 14 | 15 | System.out.println(); 16 | ECIES ecies0 = new ECIES(2, 7, 31, new int[] { 2, 9 }, 8); 17 | ecies0.decrypt(new int[] { 18, 1 }, 21); 18 | ecies0.decrypt(new int[] { 3, 1 }, 18); 19 | ecies0.decrypt(new int[] { 17, 0 }, 19); 20 | ecies0.decrypt(new int[] { 28, 0 }, 8); 21 | } 22 | 23 | public ECIES(int a, int b, int p, int[] P, int m) { 24 | this.a = a; 25 | this.b = b; 26 | this.p = p; 27 | this.P = P; 28 | this.m = m; 29 | } 30 | 31 | public void encrypt(int x) { 32 | // 计算Q=kP 33 | int[] Q = P; 34 | for (int i = 0; i < m - 1; ++i) { 35 | Q = add(Q, P); 36 | } 37 | System.out.println(Q[0] + " " + Q[1]); 38 | 39 | // 随机选取秘密整数k 40 | //int k = (int) (Math.random() * p + 1); 41 | //System.out.println("k" + " " + k); 42 | int k = 6; 43 | 44 | // 计算kP和kQ 45 | int[] kP = P; 46 | int[] kQ = Q; 47 | for (int i = 0; i < k - 1; ++i) { 48 | kP = add(kP, P); 49 | } 50 | for (int i = 0; i < k - 1; ++i) { 51 | kQ = add(kQ, Q); 52 | } 53 | 54 | // 计算y1和y2,y1的y坐标要模2进行压缩 55 | int[] y1 = kP; 56 | int y2 = (x * kQ[0]) % p; 57 | y1[1] = y1[1] % 2; 58 | 59 | System.out.println("加密为:" + "(" + "(" + y1[0] + "," + y1[1] + ")" + "," + y2 + ")"); 60 | } 61 | 62 | public void decrypt(int[] y1, int y2) { 63 | // 把x带入椭圆曲线求出z值 64 | int z = (y1[0] * y1[0] * y1[0] + a * y1[0] + b) % p; 65 | 66 | // 用Euler判别式计算pow(z,(p-1)/2)(mod p),以此判断z是不是模p的二次剩余 67 | int modPow = z; 68 | for (int i = 0; i < (p - 1) / 2 - 1; ++i) { 69 | modPow = (modPow * z) % p; 70 | } 71 | 72 | // 如果是二次剩余,利用pow(z,(p+1)/4)(mod p),把z开方 73 | if (modPow == 1) { 74 | // 计算pow(z,(p+1)/4)(mod p) 75 | int y = z; 76 | for (int i = 0; i < (p + 1) / 4 - 1; ++i) { 77 | y = y * z % p; 78 | } 79 | 80 | // 重构E上的点y1,判断根号z模2是否和y1的i值相等,如果相等就用i=y重构点y1 81 | if (y % 2 == y1[1]) { 82 | y1[1] = y; 83 | } else { 84 | y1[1] = p - y; 85 | } 86 | 87 | // 计算m*kP,kP由重构得到,PD即Point-Decompress 88 | int[] PD = y1; 89 | for (int i = 0; i < m - 1; ++i) { 90 | PD = add(PD, y1); 91 | } 92 | 93 | // 利用y2,和mkP的x值进行解密 94 | int x = (y2 * Euclidean(p, PD[0])) % p; 95 | System.out.println("解密为:" + x + (char) (x % 26 + 64)); 96 | } else { 97 | System.out.println("failure"); 98 | } 99 | } 100 | 101 | public int[] add(int[] P, int[] Q) { 102 | int[] R = new int[] { 0, 0 }; // 用(0,0)代表无穷远点 103 | 104 | // 如果至少一个点为无穷远点,则返回原值 105 | // 如果互为加法逆点,则相加为无穷远点 106 | // 否则通过表达式计算相加后的值 107 | if (P[0] == 0 && P[1] == 0) { 108 | return Q; 109 | } else if (Q[0] == 0 && Q[1] == 0) { 110 | return P; 111 | } else if (P[0] == Q[0] && P[1] == -Q[1]) { 112 | System.out.println("相加为无穷远点"); 113 | } else { 114 | int lambda; 115 | if (P[0] == Q[0] && P[1] == Q[1]) { 116 | lambda = Euclidean(p, (2 * P[1]) % p); 117 | lambda = lambda * (3 * P[0] * P[0] + a) % p; 118 | } else { 119 | lambda = Euclidean(p, (Q[0] - P[0] + p) % p); 120 | lambda = (lambda * (Q[1] - P[1] + p)) % p; 121 | } 122 | R[0] = (lambda * lambda - P[0] - Q[0]) % p; 123 | R[1] = (lambda * (P[0] - R[0]) - P[1]) % p; 124 | while (R[0] < 0) { 125 | R[0] += p; 126 | } 127 | while (R[1] < 0) { 128 | R[1] += p; 129 | } 130 | } 131 | return R; 132 | } 133 | 134 | public int Euclidean(int a, int b) { 135 | int a0 = a; 136 | int b0 = b; 137 | int t0 = 0; 138 | int t = 1; 139 | int q = (int) Math.floor((double) a0 / b0); 140 | int r = a0 - q * b0; 141 | while (r > 0) { 142 | int temp = (t0 - q * t) % a; 143 | t0 = t; 144 | t = temp; 145 | a0 = b0; 146 | b0 = r; 147 | q = (int) Math.floor((double) a0 / b0); 148 | r = a0 - q * b0; 149 | } 150 | if (b0 != 1) { 151 | System.out.println("没有逆元!"); 152 | } 153 | while (t < 0) { 154 | t += a; 155 | } 156 | return t; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /SixthUnit/ElGamal.java: -------------------------------------------------------------------------------- 1 | package sixthUnit; 2 | 3 | public class ElGamal { 4 | private int p; 5 | private int alphi; 6 | private int a; 7 | private int beta; 8 | 9 | public static void main(String[] args) { 10 | ElGamal elgamal = new ElGamal(31847, 5, 7899, 18074); 11 | elgamal.decrypt(3781, 14409); 12 | elgamal.decrypt(31552, 3930); 13 | elgamal.decrypt(27214, 15442); 14 | elgamal.decrypt(5809, 30274); 15 | } 16 | 17 | public ElGamal(int p, int alphi, int a, int beta) { 18 | this.p = p; 19 | this.alphi = alphi; 20 | this.a = a; 21 | this.beta = beta; 22 | } 23 | 24 | public void encrypt(int x) { 25 | int k = (int) (Math.random() * (p - 1) + 1); 26 | int y1 = alphi, y2 = x; 27 | for (int i = 0; i < k - 1; ++i) { 28 | y1 = (y1 * alphi) % p; 29 | } 30 | for (int i = 0; i < k; ++i) { 31 | y2 = (y2 * beta) % p; 32 | } 33 | System.out.println("(" + y1 + "," + y2 + ")"); 34 | } 35 | 36 | public void decrypt(int y1, int y2) { 37 | int x = y1; 38 | for (int i = 0; i < a - 1; ++i) { 39 | x = (x * y1) % p; 40 | } 41 | x = Euclidean(p, x); 42 | x = (y2 * x) % p; 43 | char[] text = new char[3]; 44 | 45 | text[0] = (char) (x / 676 + 65); 46 | x = x - x / 676 * 676; 47 | text[1] = (char) (x / 26 + 65); 48 | x = x - x / 26 * 26; 49 | text[2] = (char) (x % 26 + 65); 50 | for (char c : text) { 51 | System.out.print(c); 52 | } 53 | System.out.print(" "); 54 | } 55 | 56 | public int Euclidean(int a, int b) { 57 | int a0 = a; 58 | int b0 = b; 59 | int t0 = 0; 60 | int t = 1; 61 | int q = (int) Math.floor((double) a0 / b0); 62 | int r = a0 - q * b0; 63 | while (r > 0) { 64 | int temp = (t0 - q * t) % a; 65 | t0 = t; 66 | t = temp; 67 | a0 = b0; 68 | b0 = r; 69 | q = (int) Math.floor((double) a0 / b0); 70 | r = a0 - q * b0; 71 | } 72 | if (b0 != 1) { 73 | System.out.println("没有逆元!"); 74 | } 75 | while (t < 0) { 76 | t += a; 77 | } 78 | return t; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /SixthUnit/Shanks.java: -------------------------------------------------------------------------------- 1 | package sixthUnit; 2 | 3 | import java.util.Arrays; 4 | 5 | public class Shanks { 6 | 7 | public static void main(String[] args) { 8 | Shanks shanks = new Shanks(); 9 | int n, alphi, beta; 10 | 11 | n = 24691; 12 | alphi = 106; 13 | beta = 12375; 14 | shanks.shanks(n, alphi, beta); 15 | 16 | n = 458009; 17 | alphi = 6; 18 | beta = 248388; 19 | shanks.shanks(n, alphi, beta); 20 | } 21 | 22 | public void shanks(int p, int alphi, int beta) { 23 | int m = (int) Math.ceil(Math.sqrt(p - 1)); 24 | long[] aj = new long[m]; 25 | long[] bi = new long[m]; 26 | int i, j; 27 | 28 | // 首先计算alphi的m次方 29 | int aTemp = alphi; 30 | for (i = 0; i < m - 1; ++i) { 31 | aTemp = (aTemp * alphi) % p; 32 | //System.out.println(aTemp); 33 | } 34 | 35 | // 计算alphi的mj次方,得到列表aj 36 | // 然后复制表aj得到ajCopy,将ajCopy排序 37 | aj[0] = 1; 38 | for (j = 1; j < m; ++j) { 39 | aj[j] = (aj[j - 1] * aTemp) % p; 40 | //System.out.println(aj[j]); 41 | } 42 | long[] ajCopy = Arrays.copyOf(aj, aj.length); 43 | Arrays.sort(ajCopy); 44 | 45 | // 计算alphi的-i次方,得到列表bi 46 | // 然后复制表bi得到biCopy,将biCopy排序 47 | bi[0] = beta; 48 | int bTemp = Euclidean(p, alphi); 49 | for (i = 1; i < m; ++i) { 50 | bi[i] = (bi[i - 1] * bTemp) % p; 51 | } 52 | long[] biCopy = Arrays.copyOf(bi, bi.length); 53 | Arrays.sort(biCopy); 54 | 55 | // 寻找ajCopy和biCopy中相等的值 56 | i = 0; 57 | j = 0; 58 | long same = 0; 59 | boolean isFound = false; 60 | while (i < m && j < m) { 61 | if (ajCopy[j] < biCopy[i]) { 62 | ++j; 63 | } else if (ajCopy[j] > biCopy[i]) { 64 | ++i; 65 | } else { 66 | isFound = true; 67 | same = ajCopy[j]; 68 | break; 69 | } 70 | } 71 | 72 | // 如果找到了相等值就计算log 73 | if (isFound) { 74 | i = 0; 75 | j = 0; 76 | while (aj[j] != same) { 77 | ++j; 78 | } 79 | while (bi[i] != same) { 80 | ++i; 81 | } 82 | System.out.println("p:" + p + "\nalphi:" + alphi + "\nbeta:" + beta + "\nlog:" + (m * j + i) % p + "\n"); 83 | } else { 84 | System.out.println("没有结果"); 85 | } 86 | } 87 | 88 | // 扩展欧几里得算法,求逆元 89 | public int Euclidean(int a, int b) { 90 | int a0 = a; 91 | int b0 = b; 92 | int t0 = 0; 93 | int t = 1; 94 | int q = (int) Math.floor((double) a0 / b0); 95 | int r = a0 - q * b0; 96 | while (r > 0) { 97 | int temp = (t0 - q * t) % a; 98 | t0 = t; 99 | t = temp; 100 | a0 = b0; 101 | b0 = r; 102 | q = (int) Math.floor((double) a0 / b0); 103 | r = a0 - q * b0; 104 | } 105 | if (b0 != 1) { 106 | System.out.println("没有逆元!"); 107 | } 108 | while (t < 0) { 109 | t += a; 110 | } 111 | return t; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /ThirdUnit/AES.java: -------------------------------------------------------------------------------- 1 | package ThirdUnit; 2 | 3 | import java.util.*; 4 | 5 | public class AES { 6 | public static void main(String[] args) { 7 | String key = "2B7E151628AED2A6ABF7158809CF4F3C"; // 密钥 8 | String plaintText = "3243F6A8885A308D313198A2E0370734"; // 明文 9 | 10 | AES aes = new AES(); 11 | aes.encrypt(key, plaintText); 12 | } 13 | 14 | // 一 加密 15 | public void encrypt(String key, String plaintText) { 16 | // 1 明文分组 17 | ArrayList subPlaintText = new ArrayList(); 18 | for (int i = 0; i < 30; i += 8) { 19 | subPlaintText.add(new StringBuffer(plaintText.substring(i, i + 8))); 20 | } 21 | 22 | // 2 扩展密钥 23 | ArrayList w = keyExpansion(key); 24 | 25 | // 3 前9轮操作 26 | for (int i = 0; i < 10; ++i) { 27 | // 3.1 轮密钥加->字节替换 28 | for (int j = 0; j < 4; ++j) { 29 | // 3.1.1 轮密钥异或 30 | subPlaintText.set(j, 31 | new StringBuffer(Long.toHexString(Long.parseLong(subPlaintText.get(j).toString(), 16) 32 | ^ Long.parseLong(w.get(i * 4 + j).toString(), 16)))); 33 | while (subPlaintText.get(j).length() != 8) { 34 | subPlaintText.get(j).insert(0, 0); 35 | } 36 | 37 | // 3.1.2 字节替换 38 | for (int k = 0; k < 6; k += 2) { 39 | subPlaintText.get(j).replace(k, k + 2, subBytes(subPlaintText.get(j).substring(k, k + 2))); 40 | } 41 | subPlaintText.get(j).replace(6, 8, subBytes(subPlaintText.get(j).substring(6))); 42 | } 43 | 44 | // 3.2 列移位 45 | String[][] mBytesTemp1 = new String[4][4]; 46 | for (int j = 0; j < 4; ++j) { 47 | for (int k = 0; k < 6; k += 2) { 48 | mBytesTemp1[j][k / 2] = subPlaintText.get(j).substring(k, k + 2); 49 | } 50 | mBytesTemp1[j][3] = subPlaintText.get(j).substring(6); 51 | } 52 | for (int j = 0; j < 4; ++j) { 53 | StringBuffer mRawShiftTemp = new StringBuffer(); 54 | for (int k = 0; k < 4; ++k) { 55 | mRawShiftTemp.append(mBytesTemp1[(j + k) % 4][k]); 56 | } 57 | subPlaintText.set(j, mRawShiftTemp); 58 | } 59 | 60 | // 3.2 行混淆,最后一轮不用混淆 61 | if (i != 9) { 62 | // 3.2.1 列混淆操作 63 | long[][] field = { { 2, 3, 1, 1 }, { 1, 2, 3, 1 }, { 1, 1, 2, 3 }, { 3, 1, 1, 2 } }; 64 | long[][] mBytesTemp2 = new long[4][4]; 65 | long[][] mBytesTemp3 = new long[4][4]; 66 | for (int j = 0; j < 4; ++j) { 67 | for (int k = 0; k < 6; k += 2) { 68 | mBytesTemp2[j][k / 2] = Long.parseLong(subPlaintText.get(j).substring(k, k + 2), 16); 69 | } 70 | mBytesTemp2[j][3] = Long.parseLong(subPlaintText.get(j).substring(6), 16); 71 | } 72 | for (int j = 0; j < 4; ++j) { // 明文的行 73 | for (int k = 0; k < 4; ++k) { // field的行,明文的列 74 | long[] mMultiTemp = new long[4]; 75 | for (int l = 0; l < 4; ++l) { // field的列,明文的列 76 | if (field[k][l] == 1) { 77 | mMultiTemp[l] = mBytesTemp2[j][l]; 78 | } else if (field[k][l] == 2) { 79 | if (mBytesTemp2[j][l] < 128) { 80 | mMultiTemp[l] = mBytesTemp2[j][l] * 2; 81 | } else { 82 | mMultiTemp[l] = (mBytesTemp2[j][l] * 2) ^ 27; 83 | } 84 | } else if (field[k][l] == 3) { 85 | long mTemp; 86 | if (mBytesTemp2[j][l] < 128) { 87 | mTemp = mBytesTemp2[j][l] * 2; 88 | } else { 89 | mTemp = (mBytesTemp2[j][l] * 2) ^ 27; 90 | } 91 | mMultiTemp[l] = mBytesTemp2[j][l] ^ mTemp; 92 | } 93 | } 94 | mBytesTemp3[j][k] = (mMultiTemp[0] ^ mMultiTemp[1] ^ mMultiTemp[2] ^ mMultiTemp[3]) % 256; 95 | } 96 | } 97 | 98 | // 3.2.2 赋给subPlaintText 99 | for (int j = 0; j < 4; ++j) { 100 | StringBuffer mTemp = new StringBuffer(); 101 | for (int k = 0; k < 4; ++k) { 102 | StringBuffer temp = new StringBuffer(Long.toHexString(mBytesTemp3[j][k])); 103 | while (temp.length() < 2) { 104 | temp.insert(0, 0); 105 | } 106 | mTemp.append(temp); 107 | } 108 | subPlaintText.set(j, mTemp); 109 | } 110 | } 111 | 112 | // 4 最后一轮操作 113 | if (i == 9) { 114 | System.out.println("加密结果为"); 115 | for (int j = 0; j < 4; ++j) { 116 | subPlaintText.set(j, 117 | new StringBuffer(Long.toHexString(Long.parseLong(subPlaintText.get(j).toString(), 16) 118 | ^ Long.parseLong(w.get((i + 1) * 4 + j).toString(), 16)))); 119 | while (subPlaintText.get(j).length() != 8) { 120 | subPlaintText.get(j).insert(0, 0); 121 | } 122 | System.out.println(subPlaintText.get(j)); 123 | } 124 | } 125 | } 126 | } 127 | 128 | /////////////////////////////////////////////////////////////////////////////////// 129 | /////////////////////////////////////////////////////////////////////////////////// 130 | 131 | // 二 密钥的编排 132 | public ArrayList keyExpansion(String key) { 133 | final String[] Rcon = { "01000000", "2000000", "04000000", "08000000", "10000000", "20000000", "40000000", 134 | "80000000", "1B000000", "36000000" }; 135 | ArrayList w = new ArrayList(); // 扩展后的轮密钥 136 | ArrayList subKey = new ArrayList();// 存储分组后的密钥 137 | 138 | // 1 把密钥分成16组,每组两个十六进制数,1个字节 139 | for (int i = 0; i < 32; i += 2) { 140 | subKey.add(key.substring(i, i + 2)); 141 | } 142 | 143 | // 2 填入w 144 | for (int i = 0; i < 4; ++i) { 145 | StringBuffer mWTemp = new StringBuffer(); 146 | for (int j = 0; j < 4; ++j) { 147 | mWTemp.append(subKey.get(4 * i + j)); 148 | } 149 | w.add(mWTemp); 150 | } 151 | 152 | // 3 填入w 153 | StringBuffer temp = new StringBuffer(); 154 | for (int i = 4; i < 44; ++i) { 155 | temp.replace(0, temp.length(), w.get(i - 1).toString()); 156 | if (i % 4 == 0) { 157 | temp.replace(0, temp.length(), Long.toHexString( 158 | Long.parseLong(subWord(rotWord(temp)).toString(), 16) ^ Long.parseLong(Rcon[i / 4 - 1], 16))); 159 | } 160 | w.add(new StringBuffer(Long.toHexString( 161 | (Long.parseLong(w.get(i - 4).toString(), 16)) ^ (Long.parseLong(temp.toString(), 16))))); 162 | } 163 | return w; 164 | } 165 | 166 | // 对四个字节进行循环移位 167 | public String rotWord(StringBuffer temp) { 168 | String firstOne = temp.substring(0, 2); 169 | String lastThree = temp.substring(2); 170 | StringBuffer mTemp = new StringBuffer(); 171 | mTemp.append(lastThree); 172 | mTemp.append(firstOne); 173 | return mTemp.toString(); 174 | } 175 | 176 | // 对四个字节使用S盒映射 177 | public StringBuffer subWord(String temp) { 178 | StringBuffer mTemp = new StringBuffer(); 179 | for (int i = 0; i < 8; i += 2) { 180 | if (i != 6) { 181 | mTemp.append(subBytes(temp.substring(i, i + 2).toString())); 182 | } else { 183 | mTemp.append(subBytes(temp.substring(6).toString())); 184 | } 185 | } 186 | return mTemp; 187 | } 188 | 189 | // S盒的映射 190 | public String subBytes(String temp) { 191 | final String SBox[][] = { 192 | { "63", "7C", "77", "7B", "F2", "6B", "6F", "C5", "30", "01", "67", "2B", "FE", "D7", "AB", "76" }, 193 | { "CA", "82", "C9", "7D", "FA", "59", "47", "F0", "AD", "D4", "A2", "AF", "9C", "A4", "72", "C0" }, 194 | { "B7", "FD", "93", "26", "36", "3F", "F7", "CC", "34", "A5", "E5", "F1", "71", "D8", "31", "15" }, 195 | { "04", "C7", "23", "C3", "18", "96", "05", "9A", "07", "12", "80", "E2", "EB", "27", "B2", "75" }, 196 | { "09", "83", "2C", "1A", "1B", "6E", "5A", "A0", "52", "3B", "D6", "B3", "29", "E3", "2F", "84" }, 197 | { "53", "D1", "00", "ED", "20", "FC", "B1", "5B", "6A", "CB", "BE", "39", "4A", "4C", "58", "CF" }, 198 | { "D0", "EF", "AA", "FB", "43", "4D", "33", "85", "45", "F9", "02", "7F", "50", "3C", "9F", "A8" }, 199 | { "51", "A3", "40", "8F", "92", "9D", "38", "F5", "BC", "B6", "DA", "21", "10", "FF", "F3", "D2" }, 200 | { "CD", "0C", "13", "EC", "5F", "97", "44", "17", "C4", "A7", "7E", "3D", "64", "5D", "19", "73" }, 201 | { "60", "81", "4F", "DC", "22", "2A", "90", "88", "46", "EE", "B8", "14", "DE", "5E", "0B", "DB" }, 202 | { "E0", "32", "3A", "0A", "49", "06", "24", "5C", "C2", "D3", "AC", "62", "91", "95", "E4", "79" }, 203 | { "E7", "C8", "37", "6D", "8D", "D5", "4E", "A9", "6C", "56", "F4", "EA", "65", "7A", "AE", "08" }, 204 | { "BA", "78", "25", "2E", "1C", "A6", "B4", "C6", "E8", "DD", "74", "1F", "4B", "BD", "8B", "8A" }, 205 | { "70", "3E", "B5", "66", "48", "03", "F6", "0E", "61", "35", "57", "B9", "86", "C1", "1D", "9E" }, 206 | { "E1", "F8", "98", "11", "69", "D9", "8E", "94", "9B", "1E", "87", "E9", "CE", "55", "28", "DF" }, 207 | { "8C", "A1", "89", "0D", "BF", "E6", "42", "68", "41", "99", "2D", "0F", "B0", "54", "BB", "16" } }; 208 | return SBox[Integer.valueOf(temp.substring(0, 1), 16)][Integer.valueOf(temp.substring(1), 16)]; 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /ThirdUnit/DES.java: -------------------------------------------------------------------------------- 1 | package ThirdUnit; 2 | 3 | public class DES { 4 | // 置换IP表 5 | private int[] IP_Table = { 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6 | 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 7 | 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 }; 8 | // 逆置换IP-1表 9 | private int[] IPR_Table = { 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 10 | 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 11 | 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25 }; 12 | // E位选择表(扩展置换表) 13 | private int[] E_Table = { 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 14 | 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1 }; 15 | // P换位表(单纯换位表) 16 | private int[] P_Table = { 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 17 | 19, 13, 30, 6, 22, 11, 4, 25 }; 18 | // PC1选位表(密钥生成置换表1) 19 | private int[] PC1_Table = { 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 20 | 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 21 | 5, 28, 20, 12, 4 }; 22 | // PC2选位表(密钥生成置换表2) 23 | private int[] PC2_Table = { 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 24 | 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 }; 25 | // 左移位数表 26 | private int[] LOOP_Table = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; 27 | // S盒 28 | private int[][] S_Box = { 29 | // S1 30 | { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 31 | 8, 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 32 | 0, 6, 13 }, 33 | // S2 34 | { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 35 | 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 36 | 5, 14, 9 }, 37 | // S3 38 | { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 39 | 1, 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 40 | 5, 2, 12 }, 41 | // S4 42 | { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 43 | 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 44 | 7, 2, 14 }, 45 | // S5 46 | { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 47 | 6, 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 48 | 10, 4, 5, 3 }, 49 | // S6 50 | { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 51 | 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 52 | 0, 8, 13 }, 53 | // S7 54 | { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 55 | 6, 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 56 | 2, 3, 12 }, 57 | // S8 58 | { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 59 | 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 60 | 5, 6, 11 } }; 61 | 62 | public static void main(String[] args) { 63 | String plaintext = "abcdefgh"; 64 | String key = "aaaaaaaa"; 65 | DES des = new DES(); 66 | String ciphertext = des.encrypt(plaintext, key, "encrypt"); 67 | System.out.println("明文为:" + plaintext + "\n密钥为:" + key + "\n加密为:" + ciphertext + "\n"); 68 | System.out.println("解密为:" + des.encrypt(ciphertext, key, "decrypt")); 69 | } 70 | 71 | // 1 子密钥生成 72 | public StringBuffer[] getSubKey(String key) { 73 | StringBuffer[] subKey = new StringBuffer[16]; // 存储子密钥 74 | 75 | // 1.1 把密钥转换成二进制字符串 76 | StringBuffer keyBinary = new StringBuffer(); // 存储转换后的二进制密钥 77 | for (int i = 0; i < 8; ++i) { 78 | StringBuffer mSubKeyTemp = new StringBuffer(Integer.toBinaryString(key.charAt(i))); 79 | while (mSubKeyTemp.length() < 8) { 80 | mSubKeyTemp.insert(0, 0); 81 | } 82 | keyBinary.append(mSubKeyTemp); 83 | } 84 | 85 | // 1.2 通过PC1置换密钥 86 | StringBuffer substituteKey = new StringBuffer(); // 存储PC1置换后的密钥 87 | for (int i = 0; i < 56; ++i) { 88 | substituteKey.append(keyBinary.charAt(PC1_Table[i] - 1)); 89 | } 90 | 91 | // 1.3 分成左右两块C0和D0 92 | StringBuffer C0 = new StringBuffer(); // 存储密钥左块 93 | StringBuffer D0 = new StringBuffer(); // 存储密钥右块 94 | C0.append(substituteKey.substring(0, 28)); 95 | D0.append(substituteKey.substring(28)); 96 | 97 | // 1.4 循环16轮生成子密钥 98 | for (int i = 0; i < 16; ++i) { 99 | // 根据LOOP_Table循环左移 100 | for (int j = 0; j < LOOP_Table[i]; ++j) { 101 | char mTemp; 102 | mTemp = C0.charAt(0); 103 | C0.deleteCharAt(0); 104 | C0.append(mTemp); 105 | mTemp = D0.charAt(0); 106 | D0.deleteCharAt(0); 107 | D0.append(mTemp); 108 | } 109 | 110 | // 把左右两块合并 111 | StringBuffer C0D0 = new StringBuffer(C0.toString() + D0.toString()); 112 | 113 | // 根据PC2压缩C0D0,得到子密钥 114 | StringBuffer C0D0Temp = new StringBuffer(); 115 | for (int j = 0; j < 48; ++j) { 116 | C0D0Temp.append(C0D0.charAt(PC2_Table[j] - 1)); 117 | } 118 | 119 | // 把子密钥存储到数组中 120 | subKey[i] = C0D0Temp; 121 | } 122 | return subKey; 123 | } 124 | 125 | // 2 加密 126 | public String encrypt(String plaintext, String key, String type) { 127 | StringBuffer ciphertext = new StringBuffer(); // 存储密文 128 | 129 | // 2.1 把明文转换成二进制字符串 130 | StringBuffer plaintextBinary = new StringBuffer(); // 存储明文二进制 131 | for (int i = 0; i < 8; ++i) { 132 | StringBuffer mSubPlaintextTemp = new StringBuffer(Integer.toBinaryString(plaintext.charAt(i))); 133 | while (mSubPlaintextTemp.length() < 8) { 134 | mSubPlaintextTemp.insert(0, 0); 135 | } 136 | plaintextBinary.append(mSubPlaintextTemp); 137 | } 138 | 139 | // 2.2 通过IP置换明文 140 | StringBuffer substitutePlaintext = new StringBuffer(); // 存储置换后的明文 141 | for (int i = 0; i < 64; ++i) { 142 | substitutePlaintext.append(plaintextBinary.charAt(IP_Table[i] - 1)); 143 | } 144 | 145 | // 2.3 把置换后的明文分为左右两块 146 | StringBuffer L = new StringBuffer(substitutePlaintext.substring(0, 32)); 147 | StringBuffer R = new StringBuffer(substitutePlaintext.substring(32)); 148 | 149 | // 2.4 得到子密钥 150 | StringBuffer[] subKey = getSubKey(key); 151 | if (type.equals("decrypt")) { 152 | StringBuffer[] mTemp = getSubKey(key); 153 | for (int i = 0; i < 16; ++i) { 154 | subKey[i] = mTemp[15 - i]; 155 | } 156 | } 157 | 158 | // 2.5 进行16轮迭代 159 | for (int i = 0; i < 16; ++i) { 160 | StringBuffer mLTemp = new StringBuffer(L); // 存储原来的左边 161 | 162 | // 左边的操作 163 | L.replace(0, 32, R.toString()); 164 | 165 | // 按E位选择表扩展右边 166 | StringBuffer mRTemp = new StringBuffer(); // 存储扩展后的右边 167 | for (int j = 0; j < 48; ++j) { 168 | mRTemp.append(R.charAt(E_Table[j] - 1)); 169 | } 170 | 171 | // 扩展后的右边和子密钥异或 172 | for (int j = 0; j < 48; ++j) { 173 | if (mRTemp.charAt(j) == subKey[i].charAt(j)) { 174 | mRTemp.replace(j, j + 1, "0"); 175 | } else { 176 | mRTemp.replace(j, j + 1, "1"); 177 | } 178 | } 179 | 180 | // 进行S盒压缩 181 | R.setLength(0); 182 | for (int j = 0; j < 8; ++j) { 183 | String mSNumber = mRTemp.substring(j * 6, (j + 1) * 6); 184 | int row = Integer.parseInt(Character.toString(mSNumber.charAt(0)) + mSNumber.charAt(5), 2); 185 | int column = Integer.parseInt(mSNumber.substring(1, 5), 2); 186 | int number = S_Box[j][row * 16 + column]; 187 | StringBuffer numberString = new StringBuffer(Integer.toBinaryString(number)); 188 | while (numberString.length() < 4) { 189 | numberString.insert(0, 0); 190 | } 191 | R.append(numberString); 192 | } 193 | 194 | // 将压缩后的R通过P_Table置换 195 | StringBuffer mRTemp1 = new StringBuffer(); // 存储置换后的R 196 | for (int j = 0; j < 32; ++j) { 197 | mRTemp1.append(R.charAt(P_Table[j] - 1)); 198 | } 199 | R.replace(0, 32, mRTemp1.toString()); 200 | 201 | // 将置换后的R与最开始的L异或 202 | for (int j = 0; j < 32; ++j) { 203 | if (R.charAt(j) == mLTemp.charAt(j)) { 204 | R.replace(j, j + 1, "0"); 205 | } else { 206 | R.replace(j, j + 1, "1"); 207 | } 208 | } 209 | } 210 | 211 | // 2.6 合并迭代完的L和R 212 | StringBuffer LR = new StringBuffer(R.toString() + L.toString()); 213 | 214 | // 2.7 根据IPR_Table置换LR 215 | StringBuffer mLRTemp = new StringBuffer(); // 存储置换后的LR 216 | for (int i = 0; i < 64; ++i) { 217 | mLRTemp.append(LR.charAt(IPR_Table[i] - 1)); 218 | } 219 | 220 | // 2.8 把二进制转为字符串 221 | for (int i = 0; i < 8; ++i) { 222 | String mCharTemp = mLRTemp.substring(i * 8, (i + 1) * 8); 223 | ciphertext.append((char) Integer.parseInt(mCharTemp, 2)); 224 | } 225 | return ciphertext.toString(); 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /ThirdUnit/DESECB.java: -------------------------------------------------------------------------------- 1 | package ThirdUnit; 2 | 3 | public class DESECB { 4 | // 置换IP表 5 | private int[] IP_Table = { 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6 | 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 7 | 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 }; 8 | // 逆置换IP-1表 9 | private int[] IPR_Table = { 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 10 | 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 11 | 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25 }; 12 | // E位选择表(扩展置换表) 13 | private int[] E_Table = { 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 14 | 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1 }; 15 | // P换位表(单纯换位表) 16 | private int[] P_Table = { 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 17 | 19, 13, 30, 6, 22, 11, 4, 25 }; 18 | // PC1选位表(密钥生成置换表1) 19 | private int[] PC1_Table = { 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 20 | 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 21 | 5, 28, 20, 12, 4 }; 22 | // PC2选位表(密钥生成置换表2) 23 | private int[] PC2_Table = { 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 24 | 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 }; 25 | // 左移位数表 26 | private int[] LOOP_Table = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; 27 | // S盒 28 | private int[][] S_Box = { 29 | // S1 30 | { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 31 | 8, 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 32 | 0, 6, 13 }, 33 | // S2 34 | { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 35 | 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 36 | 5, 14, 9 }, 37 | // S3 38 | { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 39 | 1, 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 40 | 5, 2, 12 }, 41 | // S4 42 | { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 43 | 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 44 | 7, 2, 14 }, 45 | // S5 46 | { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 47 | 6, 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 48 | 10, 4, 5, 3 }, 49 | // S6 50 | { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 51 | 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 52 | 0, 8, 13 }, 53 | // S7 54 | { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 55 | 6, 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 56 | 2, 3, 12 }, 57 | // S8 58 | { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 59 | 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 60 | 5, 6, 11 } }; 61 | 62 | public static void main(String[] args) { 63 | String plaintext = "abcdefgh" + "ijklmnop"; 64 | String key = "aaaaaaaa"; 65 | 66 | DESECB des = new DESECB(); 67 | String ciphertext = des.encrypt(plaintext, key, "encrypt"); 68 | 69 | System.out.println("明文为:" + plaintext + "\n密钥为:" + key + "\n加密为:" + ciphertext + "\n"); 70 | 71 | System.out.println("解密为:" + des.encrypt(ciphertext, key, "decrypt")); 72 | } 73 | 74 | // 1 子密钥生成 75 | public StringBuffer[] getSubKey(String key) { 76 | StringBuffer[] subKey = new StringBuffer[16]; // 存储子密钥 77 | 78 | // 1.1 把密钥转换成二进制字符串 79 | StringBuffer keyBinary = new StringBuffer(); // 存储转换后的二进制密钥 80 | for (int i = 0; i < 8; ++i) { 81 | StringBuffer mSubKeyTemp = new StringBuffer(Integer.toBinaryString(key.charAt(i))); 82 | while (mSubKeyTemp.length() < 8) { 83 | mSubKeyTemp.insert(0, 0); 84 | } 85 | keyBinary.append(mSubKeyTemp); 86 | } 87 | // System.out.println("密钥" + keyBinary); 88 | 89 | // 1.2 通过PC1置换密钥 90 | StringBuffer substituteKey = new StringBuffer(); // 存储PC1置换后的密钥 91 | for (int i = 0; i < 56; ++i) { 92 | substituteKey.append(keyBinary.charAt(PC1_Table[i] - 1)); 93 | } 94 | 95 | // System.out.println("PC1置换" + substituteKey); 96 | 97 | // 1.3 分成左右两块C0和D0 98 | StringBuffer C0 = new StringBuffer(); // 存储密钥左块 99 | StringBuffer D0 = new StringBuffer(); // 存储密钥右块 100 | C0.append(substituteKey.substring(0, 28)); 101 | D0.append(substituteKey.substring(28)); 102 | 103 | // System.out.println("分成左边" + C0 + " " + "右边" + D0); 104 | 105 | // 1.4 循环16轮生成子密钥 106 | for (int i = 0; i < 16; ++i) { 107 | // 根据LOOP_Table循环左移 108 | for (int j = 0; j < LOOP_Table[i]; ++j) { 109 | char mTemp; 110 | mTemp = C0.charAt(0); 111 | C0.deleteCharAt(0); 112 | C0.append(mTemp); 113 | mTemp = D0.charAt(0); 114 | D0.deleteCharAt(0); 115 | D0.append(mTemp); 116 | } 117 | // System.out.println(i + "移位" + "左边" + C0 + " " + "右边" + D0); 118 | 119 | // 把左右两块合并 120 | StringBuffer C0D0 = new StringBuffer(C0.toString() + D0.toString()); 121 | 122 | // System.out.println(i + "合并密钥" + C0D0); 123 | 124 | // 根据PC2压缩C0D0,得到子密钥 125 | StringBuffer C0D0Temp = new StringBuffer(); 126 | for (int j = 0; j < 48; ++j) { 127 | C0D0Temp.append(C0D0.charAt(PC2_Table[j] - 1)); 128 | } 129 | 130 | // System.out.println(i + "子密钥为" + C0D0Temp); 131 | 132 | // 把子密钥存储到数组中 133 | subKey[i] = C0D0Temp; 134 | } 135 | 136 | return subKey; 137 | } 138 | 139 | // 2 加密 140 | public String encrypt(String plaintext, String key, String type) { 141 | StringBuffer ciphertext = new StringBuffer(); // 存储密文 142 | 143 | // 2.1 把明文转换成二进制字符串 144 | int subPlaintext = plaintext.length() / 8; 145 | StringBuffer[] plaintextBinary = new StringBuffer[subPlaintext]; // 存储明文二进制 146 | for (int i = 0; i < subPlaintext; ++i) { 147 | plaintextBinary[i] = new StringBuffer(); 148 | for (int j = 0; j < 8; ++j) { 149 | StringBuffer mSubPlaintextTemp = new StringBuffer(Integer.toBinaryString(plaintext.charAt(i * 8 + j))); 150 | while (mSubPlaintextTemp.length() < 8) { 151 | mSubPlaintextTemp.insert(0, 0); 152 | } 153 | plaintextBinary[i].append(mSubPlaintextTemp); 154 | } 155 | } 156 | // System.out.println("明文" + plaintextBinary); 157 | 158 | for (int loop = 0; loop < subPlaintext; ++loop) { 159 | // 2.2 通过IP置换明文 160 | StringBuffer substitutePlaintext = new StringBuffer(); // 存储置换后的明文 161 | for (int i = 0; i < 64; ++i) { 162 | substitutePlaintext.append(plaintextBinary[loop].charAt(IP_Table[i] - 1)); 163 | } 164 | 165 | // System.out.println("IP" + substitutePlaintext); 166 | 167 | // 2.3 把置换后的明文分为左右两块 168 | StringBuffer L = new StringBuffer(substitutePlaintext.substring(0, 32)); 169 | StringBuffer R = new StringBuffer(substitutePlaintext.substring(32)); 170 | 171 | // System.out.println("左边" + L + "\n" + "右边" + R); 172 | 173 | // 2.4 得到子密钥 174 | StringBuffer[] subKey = getSubKey(key); 175 | if (type.equals("decrypt")) { 176 | StringBuffer[] mTemp = getSubKey(key); 177 | for (int i = 0; i < 16; ++i) { 178 | subKey[i] = mTemp[15 - i]; 179 | } 180 | } 181 | 182 | // System.out.println("密钥为"); 183 | // for (int i = 0; i < 16; ++i) { 184 | // System.out.println(subKey[i]); 185 | // } 186 | 187 | // 2.5 进行16轮迭代 188 | for (int i = 0; i < 16; ++i) { 189 | StringBuffer mLTemp = new StringBuffer(L); // 存储原来的左边 190 | 191 | // 左边的操作 192 | L.replace(0, 32, R.toString()); 193 | 194 | // 按E位选择表扩展右边 195 | StringBuffer mRTemp = new StringBuffer(); // 存储扩展后的右边 196 | for (int j = 0; j < 48; ++j) { 197 | mRTemp.append(R.charAt(E_Table[j] - 1)); 198 | } 199 | 200 | // System.out.println("右边" + mRTemp); 201 | 202 | // 扩展后的右边和子密钥异或 203 | for (int j = 0; j < 48; ++j) { 204 | if (mRTemp.charAt(j) == subKey[i].charAt(j)) { 205 | mRTemp.replace(j, j + 1, "0"); 206 | } else { 207 | mRTemp.replace(j, j + 1, "1"); 208 | } 209 | } 210 | 211 | // System.out.println("密钥" + subKey[i] + "\n" + "结果" + mRTemp + 212 | // "\n"); 213 | 214 | // 进行S盒压缩 215 | R.setLength(0); 216 | for (int j = 0; j < 8; ++j) { 217 | String mSNumber = mRTemp.substring(j * 6, (j + 1) * 6); 218 | int row = Integer.parseInt(Character.toString(mSNumber.charAt(0)) + mSNumber.charAt(5), 2); 219 | int column = Integer.parseInt(mSNumber.substring(1, 5), 2); 220 | 221 | // System.out.println("row" + row + " " + "column" + 222 | // column); 223 | 224 | int number = S_Box[j][row * 16 + column]; 225 | 226 | // System.out.println("number" + number + " " + 227 | // Integer.toBinaryString(number)); 228 | 229 | StringBuffer numberString = new StringBuffer(Integer.toBinaryString(number)); 230 | while (numberString.length() < 4) { 231 | numberString.insert(0, 0); 232 | } 233 | // System.out.println("number" + numberString); 234 | 235 | R.append(numberString); 236 | } 237 | 238 | // System.out.println("压缩后的R" + R); 239 | 240 | // 将压缩后的R通过P_Table置换 241 | StringBuffer mRTemp1 = new StringBuffer(); // 存储置换后的R 242 | for (int j = 0; j < 32; ++j) { 243 | mRTemp1.append(R.charAt(P_Table[j] - 1)); 244 | } 245 | R.replace(0, 32, mRTemp1.toString()); 246 | 247 | // System.out.println("置换后的R" + R); 248 | 249 | // 将置换后的R与最开始的L异或 250 | for (int j = 0; j < 32; ++j) { 251 | if (R.charAt(j) == mLTemp.charAt(j)) { 252 | R.replace(j, j + 1, "0"); 253 | } else { 254 | R.replace(j, j + 1, "1"); 255 | } 256 | } 257 | 258 | // System.out.println("迭代后:" + "\n左边:" + L + "\n" + "右边:" + R); 259 | } 260 | 261 | // 2.6 合并迭代完的L和R 262 | StringBuffer LR = new StringBuffer(R.toString() + L.toString()); 263 | 264 | // System.out.println("合并后" + LR); 265 | 266 | // 2.7 根据IPR_Table置换LR 267 | StringBuffer mLRTemp = new StringBuffer(); // 存储置换后的LR 268 | for (int i = 0; i < 64; ++i) { 269 | mLRTemp.append(LR.charAt(IPR_Table[i] - 1)); 270 | } 271 | 272 | // 2.8 把二进制转为字符串 273 | for (int i = 0; i < 8; ++i) { 274 | String mCharTemp = mLRTemp.substring(i * 8, (i + 1) * 8); 275 | ciphertext.append((char) Integer.parseInt(mCharTemp, 2)); 276 | } 277 | 278 | // System.out.println("密文" + mLRTemp); 279 | } 280 | 281 | return ciphertext.toString(); 282 | } 283 | } 284 | --------------------------------------------------------------------------------