zoukankan      html  css  js  c++  java
  • 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("公钥: 
    " + publicKey);
            System.err.println("私钥: 
    " + privateKey);
    
            byte[] encodedData = ECCCoder.encrypt(data, publicKey);
    
            byte[] decodedData = ECCCoder.decrypt(encodedData, privateKey);
    
            String outputStr = new String(decodedData);
            System.err.println("加密前: " + inputStr + "
    
    " + "解密后: " + outputStr);
            assertEquals(inputStr, outputStr);
        }
    
    }
    复制代码

    输出

    复制代码
    公钥: 
    MEAwEAYHKoZIzj0CAQYFK4EEAAEDLAAEAv4TwFN7vBGsqgfXk95ObV5clO7oAokHD7BdOP9YMh8ugAU21TjM2qPZ
    私钥: 
    MDICAQAwEAYHKoZIzj0CAQYFK4EEAAEEGzAZAgEBBBTYJsR3BN7TFw7JHcAHFkwNmfil7w==
    加密前: abc
    
    解密后: abc
    复制代码

    参考文档

    http://snowolf.iteye.com/blog/383412

    http://baike.baidu.com/item/%E6%A4%AD%E5%9C%86%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/10305582?sefr=cr

  • 相关阅读:
    为什么cmd拖拽文件进去时有时候带引号,有时候不带?
    Android开发学习笔记:Spinner和AutoCompleteTextView浅析
    使用Genymotion调试出现错误INSTALL_FAILED_CPU_ABI_INCOMPATIBLE解决办法
    Android Fragment完全解析,关于碎片你所需知道的一切
    国外程序员推荐:每个程序员都应该读的非编程书
    百度地图添加覆盖物与给定两点路线规划
    Android 百度地图 SDK v3.0.0 (三) 添加覆盖物Marker与InfoWindow的使用
    Unable to execute dex: Multiple dex files define 解决方法
    Android 百度地图 SDK v3.0.0 (二) 定位与结合方向传感器
    poppupwindow android
  • 原文地址:https://www.cnblogs.com/guweiwei/p/8005816.html
Copyright © 2011-2022 走看看