java非对称加密算法ECC

王佳亮

概述

信息安全基本概念:

  • ECC算法(Elliptic curve cryptography,椭圆曲线密码学

ECC

椭圆加密算法(ECC)是一种公钥加密体制,最初由Koblitz和Miller两人于1985年提出,其数学基础是利用椭圆曲线上的有理点构成Abel加法群上椭圆离散对数的计算困难性。

是目前已知的公钥体制中,对每比特所提供加密强度最高的一种体制。在软件注册保护方面起到很大的作用,一般的序列号通常由该算法产生。

ECC算法在jdk1.5后加入支持,目前仅仅只能完成密钥的生成与解析。 如果想要获得ECC算法实现,需要调用硬件完成加密/解密(ECC算法相当耗费资源,如果单纯使用CPU进行加密/解密,效率低下).

算法分类信息:

 

算法 密钥长度 默认长度 签名长度 实现的方
NONEwithECDSA 112-571 256 128 JDK/BC
RIPEMD160withECDSA 同上 256 160 BC
SHA1withECDSA ... 256 160 JDK/BC
SHA224withECDSA ... 256 224 BC
SHA256withECDSA ... 256 256 JDK/BC
SHA384withECDSA ... 256 384 JDK/BC
SHA512withECDSA ... 256 512 JDK/BC

签名示例


import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin; public class ECDSA { private static String src = "ecdsa security"; public static void main(String[] args) {  
        jdkECDSA();  
    } public static void jdkECDSA(){ try { //1.初始化密钥  KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");  
            keyPairGenerator.initialize(256);  
            KeyPair keyPair = keyPairGenerator.generateKeyPair();  
            ECPublicKey ecPublicKey = (ECPublicKey)keyPair.getPublic();  
            ECPrivateKey ecPrivateKey = (ECPrivateKey)keyPair.getPrivate(); //2.执行签名  PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(ecPrivateKey.getEncoded());  
              
            KeyFactory keyFactory = KeyFactory.getInstance("EC");  
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);  
            Signature signature = Signature.getInstance("SHA1withECDSA");  
            signature.initSign(privateKey);  
            signature.update(src.getBytes()); byte[] res = signature.sign();  
            System.out.println("签名:"+HexBin.encode(res)); //3.验证签名  X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(ecPublicKey.getEncoded());  
            keyFactory = KeyFactory.getInstance("EC");  
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);  
            signature = Signature.getInstance("SHA1withECDSA");  
            signature.initVerify(publicKey);  
            signature.update(src.getBytes()); boolean bool = signature.verify(res);  
            System.out.println("验证:"+bool);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
  
} 

加解密示例代码


package com.jd.order.util.encryption; import java.math.BigInteger; import java.security.Key; import java.security.KeyFactory; 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.HashMap; import java.util.Map; import javax.crypto.Cipher; import javax.crypto.NullCipher; import org.apache.commons.codec.binary.Base64; import sun.security.ec.ECKeyFactory; import sun.security.ec.ECPrivateKeyImpl; import sun.security.ec.ECPublicKeyImpl;

@SuppressWarnings("restriction") public class ECCCoder { public static final String ALGORITHM = "EC"; private static final String PUBLIC_KEY = "ECCPublicKey"; private static final String PRIVATE_KEY = "ECCPrivateKey"; /** * 解密<br>
     * 用私钥解密
     * 
     * @param data
     * @param key
     * @return * @throws Exception */ public static byte[] decrypt(byte[] data, String key) throws Exception { // 对密钥解密 byte[] keyBytes = decryptBASE64(key); // 取得私钥 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = ECKeyFactory.INSTANCE;

        ECPrivateKey priKey = (ECPrivateKey) keyFactory
                .generatePrivate(pkcs8KeySpec);

        ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(priKey.getS(),
                priKey.getParams()); // 对数据解密 // TODO Chipher不支持EC算法 未能实现 Cipher cipher = new NullCipher(); // Cipher.getInstance(ALGORITHM, keyFactory.getProvider());  cipher.init(Cipher.DECRYPT_MODE, priKey, ecPrivateKeySpec.getParams()); return cipher.doFinal(data);
    } /** * 加密<br>
     * 用公钥加密
     * 
     * @param data
     * @param privateKey
     * @return * @throws Exception */ public static byte[] encrypt(byte[] data, String privateKey) throws Exception { // 对公钥解密 byte[] keyBytes = decryptBASE64(privateKey); // 取得公钥 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = ECKeyFactory.INSTANCE;

        ECPublicKey pubKey = (ECPublicKey) keyFactory
                .generatePublic(x509KeySpec);

        ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(pubKey.getW(),
                pubKey.getParams()); // 对数据加密 // TODO Chipher不支持EC算法 未能实现 Cipher cipher = new NullCipher(); // Cipher.getInstance(ALGORITHM, keyFactory.getProvider());  cipher.init(Cipher.ENCRYPT_MODE, pubKey, ecPublicKeySpec.getParams()); return cipher.doFinal(data);
    } /** * 取得私钥
     * 
     * @param keyMap
     * @return * @throws Exception */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PRIVATE_KEY); return encryptBASE64(key.getEncoded());
    } /** * 取得公钥
     * 
     * @param keyMap
     * @return * @throws Exception */ public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY); return encryptBASE64(key.getEncoded());
    } /** * 初始化密钥
     * 
     * @return * @throws Exception */ public static Map<String, Object> initKey() throws Exception {
        BigInteger x1 = new BigInteger( "2fe13c0537bbc11acaa07d793de4e6d5e5c94eee8", 16);
        BigInteger x2 = new BigInteger( "289070fb05d38ff58321f2e800536d538ccdaa3d9", 16);

        ECPoint g = new ECPoint(x1, x2); // the order of generator BigInteger n = new BigInteger( "5846006549323611672814741753598448348329118574063", 10); // the cofactor int h = 2; int m = 163; int[] ks = { 7, 6, 3 };
        ECFieldF2m ecField = new ECFieldF2m(m, ks); // y^2+xy=x^3+x^2+1 BigInteger a = new BigInteger("1", 2);
        BigInteger b = new BigInteger("1", 2);

        EllipticCurve ellipticCurve = new EllipticCurve(ecField, a, b);

        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);

        Map<String, Object> keyMap = new HashMap<String, Object>(2);

        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey); return keyMap;
    } public static byte[] decryptBASE64(String data) { return Base64.decodeBase64(data);
    } public static String encryptBASE64(byte[] data) { return new String(Base64.encodeBase64(data));
    }
}

    请注意上述代码中的TODO内容,再次提醒注意,Chipher不支持EC算法 ,以上代码仅供参考。Chipher、Signature、KeyPairGenerator、KeyAgreement、SecretKey均不支持EC算法。为了确保程序能够正常执行,我们使用了NullCipher类,验证程序。 

测试示例


package com.jd.order.util.encryption; import static org.junit.Assert.assertEquals; import java.util.Map; import org.junit.Test; public class ECCCoderTest {

    @Test public void test() throws Exception {
        String inputStr = "abc"; byte[] data = inputStr.getBytes();

        Map<String, Object> keyMap = ECCCoder.initKey();

        String publicKey = ECCCoder.getPublicKey(keyMap);
        String privateKey = ECCCoder.getPrivateKey(keyMap);
        System.err.println("公钥: \n" + publicKey);
        System.err.println("私钥: \n" + privateKey); byte[] encodedData = ECCCoder.encrypt(data, publicKey); byte[] decodedData = ECCCoder.decrypt(encodedData, privateKey);

        String outputStr = new String(decodedData);
        System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
        assertEquals(inputStr, outputStr);
    }

}

输出


公钥: 
MEAwEAYHKoZIzj0CAQYFK4EEAAEDLAAEAv4TwFN7vBGsqgfXk95ObV5clO7oAokHD7BdOP9YMh8ugAU21TjM2qPZ
私钥: 
MDICAQAwEAYHKoZIzj0CAQYFK4EEAAEEGzAZAgEBBBTYJsR3BN7TFw7JHcAHFkwNmfil7w== 加密前: abc

解密后: abc