Java橢圓曲線密碼ECCUtil、ECIESUtil

hwl0420 8年前發布 | 3K 次閱讀 Java

<無詳細內容>
</div>

 

ECCUtil.java    

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECFieldF2m;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.EllipticCurve;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.NullCipher;

import sun.security.ec.ECKeyFactory;
import sun.security.ec.ECPrivateKeyImpl;
import sun.security.ec.ECPublicKeyImpl;


public class ECCUtil {


    /*
     * 注:
     * 
     * 1、橢圓曲線定義:一條橢圓曲線在射影平面上滿足方程:Y2Z+a1XYZ+a3YZ2=X3+a2X2Z+a4XZ2+a6Z3的所有點的集合,
     * 且曲線上每個點都是非奇異的。該方程又名維爾維斯特拉斯方程,橢圓曲線的形狀不是橢圓,
     * 只是因為其描述的方程類似于計算一個橢圓周長的方程。轉換到笛卡爾坐標系下的方程為: y2+a1xy+a3y = x3+a2x2+a4x+a6 
     * 
     * 橢圓曲線密碼體制來源于對橢圓曲線的研究,所謂橢圓曲線指的是由韋爾斯特拉斯(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卻是相當困難的,
     * 這個問題稱為橢圓曲線上點群的離散對數問題。橢圓曲線密碼體制正是利用這個困難問題設計而來。
     * 橢圓曲線應用到密碼學上最早是由Neal Koblitz 和Victor Miller在1985年分別獨立提出的。
     * 
     * 解橢圓曲線上的離散對數問題的最好算法是Pollard rho方法,其時間復雜度為,是完全指數階的。
     * 其中n為等式(2)中m的二進制表示的位數。當n=234, 約為2117,需要1.6x1023 MIPS 年的時間。
     * 而我們熟知的RSA所利用的是大整數分解的困難問題,目前對于一般情況下的因數分解的最好算法的時間復雜度是子指數階的,
     * 當n=2048時,需要2x1020MIPS年的時間。也就是說當RSA的密鑰使用2048位時,ECC的密鑰使用234位所獲得的安全強度還高出許多。
     * 它們之間的密鑰長度卻相差達9倍,當ECC的密鑰更大時它們之間差距將更大。
     * 更ECC密鑰短的優點是非常明顯的,隨加密強度的提高,密鑰長度變化不大。
     * 
     * 對橢圓曲線來說最流行的有限域是以素數為模的整數域(參見 模運算)GF(p),或是特征為2的伽羅華域GF(2m)。
     * 後者在專門的硬件實現上計算更為有效,而前者通常在通用處理器上更為有效。專利的問題也是相關的。
     * 一些其他素數的伽羅華域的大小和能力也已經提出了,但被密碼專家認為有一點問題。
     * 
     * 無窮遠點:射影幾何中直線有一個無窮遠點():就是無窮遠點,直線的兩端交于無窮遠點(可把直線看作封閉曲線).
     * 兩條平行的直線可以看作相交在無窮遠點,所有的平行直線都交于同一個無窮遠點·
     * 
     * Abel群:阿貝爾群也稱為交換群或可交換群,它是滿足其元素的運算不依賴于它們的次序(交換律公理)的群。
     * 阿貝爾群推廣了整數集合的加法運算。阿貝爾群以挪威數學家尼爾斯·阿貝爾命名。
     * 
     * 加法運算:任意取橢圓曲線上兩點P、Q (若P、Q兩點重合,則做P點的切線)做直線交于橢圓曲線的另一點R’,
     * 過R’做y軸的平行線交于R。我們規定P+Q=R。
     * 
     * 階:橢圓曲線上一點P,存在正整數n,使得nP=O∞,則n為P的階,若n不存在,則P是無限階的,
     * 有限域上定義的橢圓曲線上所有點的階都存在。O∞+P=P,O∞為零元;曲線上三個點A,B,C處于一條直線上,則A+B+C=O∞;
     * 
     * 2、加密過程
     * A選定一條橢圓曲線Ep(a,b),并取曲線上一點作為基點G
     * A選擇一個私鑰k,并生成公鑰K=kG
     * A將Ep(a,b)和k,G發送給B
     * B收到后將明文編碼到Ep(a,b)上一點M,并產生一個隨機數r
     * B計算點C1=M+rK,C2=rG
     * B將C1,C2傳給A
     * A計算C1-kC2=M+rkG-krG=M
     * A對M解碼得到明文
     * 攻擊者只能得到Ep(a,b),G,K,C1,C2,沒有k就無法得到M。
     * 
     * 簽名驗簽流程
     * A選定一條橢圓曲線Ep(a,b),并取曲線上一點作為基點G
     * A選擇一個私鑰k,并生成公鑰K=kG
     * A產生一個隨機數r,計算R(x,y)=rG
     * A計算Hash=SHA(M),M‘=M(modp)
     * A計算S=(Hash+M'k)/r(modp)
     * B獲得S和M',Ep(a,b),K,R(x,y)
     * B計算Hash=SHA(M),M'=M(modp)
     * B計算R'=(Hash*G+M'*K)/S=(Hash*G+M'*kG)*r/(Hash+M'k)=rG=R(x,y),若R'=R,則驗簽成功。
     * 以上加解密和簽名驗簽流程只是一個例子,具體應用時可以利用K=kG這一特性變幻出多種加解密方式。
     * 
     * 密鑰磋商過程:
     * 假設密鑰交換雙方為Alice、Bob,其有共享曲線參數(橢圓曲線E、階N、基點G)。
     * 1) Alice生成隨機整數a,計算A=a*G。Bob生成隨機整數b,計算B=b*G。
     * 2) Alice將A傳遞給Bob。A的傳遞可以公開,即攻擊者可以獲取A。由于橢圓曲線的離散對數問題是難題,所以攻擊者不可以通過A、G計算出a。Bob將B傳遞給Alice。同理,B的傳遞可以公開。
     * 3) Bob收到Alice傳遞的A,計算Q=b*A
     * 4) Alice收到Bob傳遞的B,計算Q‘=a*B
     * Alice、Bob雙方即得Q=b*A=b*(a*G)=(b*a)*G=(a*b)*G=a*(b*G)=a*B=Q' (交換律和結合律),即雙方得到一致的密鑰Q。
     * 
     * 加密和解密程序:ECC ElGamal和ECIES;簽名:ECRSA;密鑰磋商:ECDH
     * 
     * 3、JDK目錄僅支持密鑰的生成和解析,暫不支持加解密(使用NullCipher替換Cipher)
     */

    public static final String ALGORITHM = "EC";
    public static final String TRANSFORMATION = "EC";

    public static KeyPair generateKey() throws Exception {

        // x^163+x^7+x^6+x^3+1
        ECFieldF2m ecField = new ECFieldF2m(163, new int[]{ 7, 6, 3 }); // 有限域(finite field)// 特征為2的伽羅華域GF(2m)

        // 韋爾斯特拉斯(Weierstrass)方程: y^2+a1xy+a3y=x^3+a2x^2+a4x+a6
        // 域F2n(n>=1)上的橢圓曲線的Weierstrass方程式為:y^2+xy=x^3+a2x^2+a6 
        // y^2+xy=x^3+x^2+1 
        EllipticCurve ellipticCurve = new EllipticCurve(ecField, new BigInteger("1", 2), new BigInteger("1", 2));

        ECPoint g = new ECPoint(new BigInteger("2fe13c0537bbc11acaa07d793de4e6d5e5c94eee8", 16), 
                new BigInteger("289070fb05d38ff58321f2e800536d538ccdaa3d9", 16)); // 基點
        BigInteger n = new BigInteger("5846006549323611672814741753598448348329118574063", 10); // G的階(order of generator)
        int h = 2; // the cofactor

        ECParameterSpec ecParameterSpec = new ECParameterSpec(ellipticCurve, g, n, h);
        // 公鑰
        ECPublicKey publicKey = new ECPublicKeyImpl(g, ecParameterSpec);
        BigInteger s = new BigInteger("1234006549323611672814741753598448348329118574063", 10);
        // 私鑰
        ECPrivateKey privateKey = new ECPrivateKeyImpl(s, ecParameterSpec);

        KeyPair keyPair = new KeyPair(publicKey, privateKey);
        return keyPair;
    }

    public static byte[] encrypt(byte[] content, byte[] key) throws Exception {

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = ECKeyFactory.INSTANCE;
        ECPrivateKey privateKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
        ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(privateKey.getS(), privateKey.getParams());

        Cipher cipher = new NullCipher(); // TODO Chipher不支持EC算法 未能實現
        cipher.init(Cipher.ENCRYPT_MODE, privateKey, privateKeySpec.getParams());
        return cipher.doFinal(content);
    }

    public static byte[] decrypt(byte[] content, byte[] key) throws Exception {

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key);
        KeyFactory keyFactory = ECKeyFactory.INSTANCE;
        ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(keySpec);
        ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(publicKey.getW(), publicKey.getParams());

        Cipher cipher = new NullCipher(); // TODO Chipher不支持EC算法 未能實現
        cipher.init(Cipher.ENCRYPT_MODE, publicKey, publicKeySpec.getParams());
        return cipher.doFinal(content);
    }

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

        KeyPair keyPair = generateKey();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();

        System.out.println(privateKey);
        System.out.println(publicKey);

        System.out.println(Arrays.toString(encrypt("橢圓曲線密碼體制來源于對橢圓曲線的研究".getBytes(), privateKey.getEncoded())));
        System.out.println(new String(decrypt(encrypt("橢圓曲線密碼體制來源于對橢圓曲線的研究".getBytes(), privateKey.getEncoded()), publicKey.getEncoded())));

        /*
         * 控制臺輸出:
         *
         * sun.security.ec.ECPrivateKeyImpl@ffffe9f5
         * Sun EC public key, 163 bits
         *   public x coord: 4373527398576640063579304354969275615843559206632
         *   public y coord: 3705292482178961271312284701371585420180764402649
         *   parameters: java.security.spec.ECParameterSpec@1ea21c07
         * [-26, -92, -83, -27, -100, -122, -26, -101, -78, -25, -70, -65, -27, -81, -122, -25, -96, -127, -28, -67, -109, -27, -120, -74, -26, -99, -91, -26, -70, -112, -28, -70, -114, -27, -81, -71, -26, -92, -83, -27, -100, -122, -26, -101, -78, -25, -70, -65, -25, -102, -124, -25, -96, -108, -25, -87, -74]
         * 橢圓曲線密碼體制來源于對橢圓曲線的研究
         */
    }

}

ECIESUtil.java    

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;

import javax.crypto.Cipher;

import sun.security.ec.ECKeyFactory;


public class ECIESUtil {

    public static final String ALGORITHM = "ECIES";
    public static final String TRANSFORMATION = "ECIESwithDESede/NONE/PKCS7Padding";
    public static final String PROVIDER = "BC";

    static{
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }

    public static KeyPair generateKeyPair() throws Exception {

        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM, PROVIDER);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        return keyPair;
    }

    public static byte[] encrypt(byte[] content, byte[] key) throws Exception {

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key);
        KeyFactory keyFactory = ECKeyFactory.INSTANCE;
        ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(keySpec);

        Cipher cipher = Cipher.getInstance(TRANSFORMATION, PROVIDER);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(content);
    }

    public static byte[] decrypt(byte[] content, byte[] key) throws Exception {

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = ECKeyFactory.INSTANCE;
        ECPrivateKey privateKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);

        Cipher cipher = Cipher.getInstance(TRANSFORMATION, PROVIDER);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(content);
    }

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

        KeyPair keyPair = generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();

        System.out.println(privateKey);
        System.out.println(publicKey);

        System.out.println(Arrays.toString(encrypt("橢圓曲線密碼體制來源于對橢圓曲線的研究".getBytes(), publicKey.getEncoded())));
        System.out.println(new String(decrypt(encrypt("橢圓曲線密碼體制來源于對橢圓曲線的研究".getBytes(), publicKey.getEncoded()), privateKey.getEncoded())));

        /*
         * 控制臺輸出:
         * 
         * EC Private Key
         *              S: 29c151f9a7b46862e9ed164a0de663cf804c166db40866d2746409716add
         * 
         * EC Public Key
         *             X: 1d6cca7e4927259eba8a6ca8f6ce4fc031185b1e4ecc52244e14e41f120e
         *             Y: 56f2e545c83e63b89cb63c996dbe51caa6089c79b56e3d7cddbadfbe5e8c
         * 
         * [4, 101, -63, -123, -21, -62, -87, -78, 34, -122, 48, -122, -82, 19, -8, -128, -101, -63, 86, -97, 95, 70, -84, 27, -63, 63, -73, 73, -91, -79, 123, 75, -78, -56, -63, 37, 26, 97, 4, -90, -88, 92, 82, 105, 42, -66, 41, -62, -68, -122, 34, -106, 49, 35, 88, 92, 115, -31, 68, -80, 90, -126, 30, -100, 55, 21, -60, -96, -55, -17, 114, 78, -100, 85, 64, 47, 17, -28, 63, 67, 70, 25, -78, -116, -19, 15, 44, -84, 110, 95, 5, -35, 95, 22, 108, 95, 106, -46, -62, -100, 106, 105, 17, 33, 46, -41, 73, 25, 51, 37, 115, -56, -109, -113, 118, -35, -91, -2, -35, -108, -85, -62, -39, -112, 86, -22, 30, -8, -19, -63, 22, 105, -87, 34, 100, -112, -12, 31, -96, 81, -67, -86, -54, 3, -8]
         * 橢圓曲線密碼體制來源于對橢圓曲線的研究
         */
    }

}
 本文由用戶 hwl0420 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!