1、基本概念
1)橢圓曲線方程的一般形式:y^2 = x^3 + a*x + b,其中要求滿足不等式 4*a^3 + 27*b^2 ≠ 0
例如:y^2 = x^3 + x + 1 mod 23
2)橢圓曲線上的點的加法公式(適用於 P ≠ Q 的情況):設 P = (x1, y1),Q = (x2, y2),P + Q = R = (x3, y3),t = (y2-y1)/(x2-x1),x3 = t^2 - x1 - x2,y3 = t*(x1 - x3) - y1
3)橢圓曲線上的點的加法公式(當上面的 P = Q 時):P + P = R = (x3, y3),t = (3*x1^2+a)/(2*y1),x3 = t^2 - x1 - x1,y3 = t*(x1 - x3) - y1
2、准備步驟
1)隨機生成一個數 d 做私鑰
2)選橢圓曲線上的一個點 P,計算 Q = d*P 做公鑰
設 A 要加密 M 送給 B,B 的私鑰為 d,公鑰為 Q = d*P
3、加密過程
1)A 隨機生成一個數 k
2)計算 k*P 和 k*Q
3)取 k*Q 的橫坐標與 M 異或得到密文 C
4)A 發送 k*P 和密文 C 給 B
4、解密過程
1)B 用自己的私鑰 d 計算 d*(k*P)
2)B 用 d*(k*P) 的橫坐標與密文 C 異或得到 M
5、加密及解密的實現
1 import java.util.ArrayList; 2 import java.util.HashMap; 3 4 public class Main { 5 // 選用的橢圓曲線為 y^2 = x^3 + x + 1 mod 23 6 private static int a = 1, b = 1; 7 private static HashMap<Integer, Integer> myPoints = new HashMap<>(); 8 private static final int MAX = 255; 9 10 public static void main(String[] args) { 11 // 明文和密文數組的初始化 12 char[] myInfo = "1700802067GJQ".toCharArray(); 13 int[] i_mingwen = new int[myInfo.length]; 14 int[] miwen = new int[i_mingwen.length]; 15 char[] c_mingwen = new char[miwen.length]; 16 for (int i = 0; i < myInfo.length; i++) { 17 i_mingwen[i] = (int)myInfo[i]; 18 } 19 20 // 初始化橢圓曲線上的整數點 21 initPoints(); 22 23 // 顯示橢圓曲線上的整數點 24 // showPoints(); 25 26 // 獲取橢圓曲線上點的橫坐標集合 27 Object[] objArr = myPoints.keySet().toArray(); 28 ArrayList<Integer> myList = new ArrayList<>(); 29 for (Object o: objArr) { 30 myList.add((Integer) o); 31 } 32 33 // 隨機取橢圓曲線上一個點 34 int Px = myList.get((int)(Math.random()*myList.size())); 35 int Py = myPoints.get(Px); 36 MyPoint p = new MyPoint(Px, Py); 37 38 // 隨機取一個 8bit 的數作為私鑰 39 int d = (int)(Math.random()*MAX) + 1; 40 // 計算Q 41 MyPoint Q = new MyPoint(p); 42 myECC(Q, 1, d); 43 44 // 隨機取一個 8bit 的數k 45 int k = (int)(Math.random()*MAX) + 1; 46 47 // 計算 k*P 和 k*Q 48 MyPoint kP = new MyPoint(p); 49 myECC(kP, 1, k); 50 MyPoint kQ = new MyPoint(Q); 51 myECC(kQ, 1, k); 52 53 // 加密 54 int kQx = kQ.getX(); 55 for (int i = 0; i < i_mingwen.length; i++) { 56 miwen[i] = i_mingwen[i] ^ kQx; 57 } 58 59 // 計算d*(k*P) 60 MyPoint dkP = new MyPoint(kP); 61 myECC(dkP, 1, d); 62 63 // 解密 64 int dkPx = dkP.getX(); 65 for (int i = 0; i < miwen.length; i++) { 66 c_mingwen[i] = (char) (miwen[i] ^ dkPx); 67 } 68 69 // 輸出對密文解密后的明文 70 System.out.println(c_mingwen); 71 } 72 73 public static void initPoints() { 74 double y; 75 for (int i = 0; i < 23; i++) { 76 y = Math.sqrt((Math.pow(i, 3) + i + 1)%23); 77 if (y == (int)y) myPoints.put(i, (int)y); 78 } 79 } 80 81 public static void myECC(MyPoint p, int i, int d){ 82 if (i < d) { 83 int t = (3*(int)Math.pow(p.getX(), 2)+a)/(2*p.getY()); 84 int x = (int)(Math.pow(t, 2)) - 2*p.getX(); 85 int y = t*(p.getX() - x) - p.getY(); 86 p.setX(x); 87 p.setY(y); 88 myECC(p, i+1, d); 89 } 90 } 91 92 public static void showPoints() { 93 myPoints.forEach((k, v) -> { 94 System.out.println("key: " + k + ", " + "value: " + v); 95 }); 96 } 97 } 98 99 class MyPoint { 100 private int x; 101 private int y; 102 MyPoint() {} 103 MyPoint(int x, int y) { 104 this.x = x; 105 this.y = y; 106 } 107 MyPoint(MyPoint P) { 108 this.x = P.getX(); 109 this.y = P.getY(); 110 } 111 public void setX(int x) { 112 this.x = x; 113 } 114 public void setY(int y) { 115 this.y = y; 116 } 117 public int getX() { 118 return this.x; 119 } 120 public int getY() { 121 return this.y; 122 } 123 }
6、注解:
1)A 用 k*P 與 B 用 d*(k*P) = k*(d*P) = k*Q
2)經過兩次異或得到原文(明文)
參考文檔:
https://wenku.baidu.com/view/ff42b6610b1c59eef8c7b477.html
遇到的疑問(已解決):
1)Objct[] 數組不能直接轉換為 ArrayList。
2)函數不能返回兩個值,可以將要返回的值放入對象中,在函數中改變對象的值。
遇到的疑問(未解決):
1)P點的橫縱坐標對后續的計算並無影響,即可以不取橢圓曲線上的點。