算法

工作笔记 专栏收录该内容
18 篇文章 0 订阅
信息摘要算法
    基本知识
        Hash,一般翻译做"散列",也有直接音译为"哈希"的
        就是把任意长度的输入,变换成固定长度的输出,该输出就是散列值。
        这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,
        不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。
        简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
        MD5与SHA1都是Hash算法,MD5输出是128位的(32字符),SHA1输出是160位的(40字符),MD5比SHA1快,SHA1比MD5强度高。
        SHA1提供了四种长度的实现,如:SHA1,SHA256,SHA384,SHA512,算法相同,只是位数不同,安全性逐渐升高
    MessageDigest类(java.security.MessageDigest)
        此类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。
        信息摘要是安全的单向哈希函数,它接收任意大小的数据,输出固定长度的哈希值。
        获得实例
            static MessageDigest getInstance(String algorithm) 
                生成实现指定摘要算法的 MessageDigest 对象。 
        常用方法
            void update(byte[] input) 
                使用指定的字节数组更新摘要。(传入数据,追加,而不是替换)
            void reset() 
                重置摘要以供再次使用。 (清空数据)
            byte[] digest() 
                通过执行诸如填充之类的最终操作完成哈希计算。 (返回结果)
            byte[] digest(byte[] input) 
                使用指定的字节数组对摘要进行最后更新,然后完成摘要计算。 (快捷方法:先更新,再计算)
        注意:带key的md5加密即 将一个固定字符串和要加密的字符串拼接后进行加密 MD5(要加密的串+key)
    md5,sha1
        /**
         * 获得哈希算法的值
         * @param data
         * @param hashName 算法名称
         * @return
         */
        public static byte[] getHashValue(byte[] data,String algorithmName) {
            try {
                // 获得算法
                MessageDigest digest = MessageDigest.getInstance(algorithmName);
                // 加密数据--返回的数组为十进制结果
                return digest.digest(data);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
        /**
         * 获得MD5值
         * @param str
         * @return
         */
        public static byte[] getMD5Value(byte[] data) {
            return getHashValue(data,"md5");
        }
        /**
         * 获得sha1值
         * @param data
         * @return
         */
        public static byte[] getSHA1Value(byte[] data) {
            return getHashValue(data,"SHA-1");
        }
        /**
         * 获得sha256值
         * @param data
         * @return
         */
        public static byte[] getSHA256Value(byte[] data) {
            return getHashValue(data,"SHA-256");
        }
        



加密算法
    对称加密算法
        对称加密算法在加密和解密时使用的是同一个秘钥,使用秘钥加密,使用秘钥解密
        算法有DES,3DES,AES,安全性逐次提高
        3DES是三重数据加密算法,它相当于是对每个数据块应用三次DES加密算法
        一般步骤:
            使用 安全随机数生成器(SecureRandom)将给定密钥转换为指定长度的字节数组
            获得 密钥生成类(KeyGenerator)
            生成 密钥(SecretKey)
            使用 密码生成器(Cipher)加密/解密
        SecureRandom类(java.security.SecureRandom)
            此类提供加密的安全随机数生成器 (RNG),这个类的作用是可以通过密钥生成[指定长度]的字节数组.
            获得实例
                static SecureRandom getInstance(String algorithm) 
                    生成实现指定随机数生成器 (RNG) 算法的 SecureRandom 对象。 
                注:参数algorithm为生成随机数使用的算法,最常用的是SHA1PRNG
            常用方法
                void setSeed(byte[] seed) 
                    重新提供此随机对象的种子。 
                    注:这里的参数就是密钥,相同的密钥每次产生的随机数相同.
                static byte[] getSeed(int numBytes) 
                    返回给定的种子字节数量,该数量可使用此类用来为其自身提供种子的种子生成算法来计算。 
                void nextBytes(byte[] bytes) 
                    生成用户指定的随机字节数。 
                注:后面两个方法,都是用来生成指定长度的字节数组的
        KeyGenerator类(javax.crypto.KeyGenerator)
            此类提供(对称)密钥生成器的功能。
            获得实例
                static KeyGenerator getInstance(String algorithm) 
                    为指定算法生成一个 KeyGenerator 对象。 
            常用方法
                void init(int keysize, SecureRandom random) 
                    使用用户提供的随机源初始化此密钥生成器,使其具有确定的密钥长度。
                    keysize是随机生成器生成的字节数组的长度,aes加密可以为128/192/256
                SecretKey generateKey() 
                    生成一个密钥。 
        SecretKey接口(javax.crypto.SecretKey)
            对称加密算法使用到的密钥
            此接口不包含方法或常量。其惟一目的是分组密钥
            常用方法
                byte[] getEncoded() 
                返回基本编码格式的密钥,如果此密钥不支持编码,则返回 null。 
        Cipher类(javax.crypto.Cipher)
            此类提供了针对加密和解密的功能,可称之为加密器或解密器
            获得实例
                static Cipher getInstance(String transformation) 
                    生成一个实现指定转换的 Cipher 对象。 
            常用方法
                void init(int opmode, Key key) 
                    用密钥初始化此 cipher。 
                    opmode为初始化类型,值有
                        static int DECRYPT_MODE 
                            用于将 cipher 初始化为解密模式的常量。 
                        static int ENCRYPT_MODE 
                            用于将 cipher 初始化为加密模式的常量。 。 
                        static int UNWRAP_MODE 
                            用于将 cipher 初始化为密钥打开模式的常量。 
                        static int WRAP_MODE 
                            用于将 cipher 初始化为密钥包装模式的常量。 
                byte[] doFinal(byte[] input) 
                    按单部分操作加密或解密数据,或者结束一个多部分操作 
        DES,3DES,AES
            /**
             * @描述:对称加密/解密
             * @开发人员:likaihao
             * @开发时间:2015年10月10日 上午10:57:09
             * @param algorithmName 算法名称
             * @param isEncrypt 是否是加密
             * @param content 数据
             * @param password 密钥
             * @param keySize 密钥长度,采用密钥的前n位长度进行加密,一般对称加密都提供多种密钥长度供选择,长度越长,安全性越高,如3des提供两种密钥长度:112和168
             * @return
             */
            public static byte[] symmetricCipher(String algorithmName, boolean isEncrypt, byte[] content, byte[] password,int keySize){
                try {
                    int mode = isEncrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
                    
                    // 获得 随机数生成器,可以通过密钥生成指定长度的字节数组.
                    SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
                    secureRandom.setSeed(password);

                    // 获得 密钥生成器
                    KeyGenerator kgen = KeyGenerator.getInstance(algorithmName);
                    kgen.init(keySize, secureRandom);

                    // 获得密钥
                    SecretKey secretKey = kgen.generateKey();

                    // 获得 密码生成器
                    Cipher cipher = Cipher.getInstance(kgen.getAlgorithm());
                    cipher.init(mode, secretKey);

                    // 加密/解密
                    return cipher.doFinal(content);
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
            
            /**
             * 使用AES进行加密
             * @param content
             * @param password
             * @return
             */
            public static byte[] encryptAES(byte[] content, byte[] password) {
                int keySize = 128;
                return symmetricCipher("AES",true,content,password,keySize);
            }

            /**
             * 使用AES进行解密
             * @param content
             * @param password
             * @return
             */
            public static byte[] decryptAES(byte[] content, byte[] password) {
                int keySize = 128;
                return symmetricCipher("AES",false,content,password,keySize);
            }
            
            /**
             * 使用DES进行加密
             * @param content
             * @param password
             * @return
             */
            public static byte[] encryptDES2(byte[] content, byte[] password) {
                int keySize = 56;
                return symmetricCipher("DES",true,content,password,keySize);
            }

            /**
             * 使用DES进行解密
             * @param content
             * @param password
             * @return
             */
            public static byte[] decryptDES2(byte[] content, byte[] password) {
                int keySize = 56;
                return symmetricCipher("DES",false,content,password,keySize);
            }
            
            /**
             * 使用3DES进行加密
             * @param content
             * @param password
             * @return
             */
            public static byte[] encrypt3DES(byte[] content, byte[] password) {
                int keySize = 112;//112 , 168
                return symmetricCipher("DESede",true,content,password,keySize);
            }

            /**
             * 使用3DES进行解密
             * @param content
             * @param password
             * @return
             */
            public static byte[] decrypt3DES(byte[] content, byte[] password) {
                int keySize = 112;//112 , 168
                return symmetricCipher("DESede",false,content,password,keySize);
            }
        使用DES进行加密我在网上发现另一种加密方式,生成秘钥的方式不同,最重要的是加密的结果不同
        后来发现,应该优先使用下面的SecretKeyFactory生成密钥这种方式
        个人理解,SecretKeyFactory的方式是通过给定的密码直接加密,KeyGenerator的方式是通过给定的随机数种子先生成密钥再进行加密
        第二种
            /**
             * 使用DES进行加密(使用SecretKeyFactory获取秘钥)
             * @param data
             * @param key  加密键byte数组
             * @return
             * @throws Exception
             */
            public static byte[] encryptDES(byte[] content, byte[] password){
                try {
                    // 生成一个可信任的随机数源
                    SecureRandom sr = new SecureRandom();
         
                    // 从原始密钥数据创建DESKeySpec对象
                    DESKeySpec dks = new DESKeySpec(password);
         
                    // 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象
                    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
                    SecretKey securekey = keyFactory.generateSecret(dks);
         
                    // Cipher对象实际完成加密操作
                    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         
                    // 用密钥初始化Cipher对象
                    cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
         
                    return cipher.doFinal(content);
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
             
            /**
             * 使用DES进行解密(使用SecretKeyFactory获取秘钥)
             * @param data
             * @param key  加密键byte数组
             * @return
             * @throws Exception
             */
            public static byte[] decryptDES(byte[] data, byte[] key){
                try {
                    // 生成一个可信任的随机数源
                    SecureRandom sr = new SecureRandom();
         
                    // 从原始密钥数据创建DESKeySpec对象
                    DESKeySpec dks = new DESKeySpec(key);
         
                    // 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象
                    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
                    SecretKey securekey = keyFactory.generateSecret(dks);
         
                    // Cipher对象实际完成解密操作
                    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         
                    // 用密钥初始化Cipher对象
                    cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
         
                    return cipher.doFinal(data);
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        第二种AES加解密方式
            public static String decryptAES(byte[] value, byte[] privateKey) {
                try {
                    SecretKeySpec skeySpec = new SecretKeySpec(privateKey, "AES");
                    Cipher cipher = Cipher.getInstance("AES");
                    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
                    return new String(cipher.doFinal(value));
                } catch (Exception ex) {
                    throw new RuntimeException();
                }
            }
    非对称加密算法
        非对称加密算法需要两个密钥来进行加密和解密,使用公钥加密,使用私钥解密
        公钥是公开的,私钥是保密的,用公钥加过密的数据只能使用私钥解密,这样可以保证持有公钥的一端发送的数据不被泄露
        客户端使用公钥进行加密,服务端使用私钥进行解密.服务端将返回数据使用私钥进行加密,客户端使用公钥进行解密
        常用算法为RSA
        获得公钥和私钥
            KeyPairGenerator类(java.security.KeyPairGenerator)
                此类用于生成公钥和私钥对
                获得实例
                    static KeyPairGenerator getInstance(String algorithm) 
                        生成实现指定摘要算法的 KeyPairGenerator 对象。 
                常用方法
                    void initialize(int keysize) 
                        初始化确定密钥大小的密钥对生成器,使用默认的参数集合并使用提供程序(以最高优先级安装)的 SecureRandom 实现作为随机源。 
                    KeyPair genKeyPair() 
                        生成密钥对。与generateKeyPair等效
                    KeyPair generateKeyPair() 
                        生成一个密钥对。 与genKeyPair等效
            KeyPair类(java.security.KeyPair)
                存放公钥和私钥
                常用方法
                    PrivateKey getPrivate() 
                        返回对此密钥对的私钥组件的引用。 
                    PublicKey getPublic() 
                        返回对此密钥对的公钥组件的引用。 
        加密和解密
            一般步骤:
                获得 X509EncodedKeySpec对象/PKCS8EncodedKeySpec对象
                使用 密钥工厂类(KeyFactory) 将 上面的对象转换为 公钥/私钥对象
                使用 密码生成器(Cipher)加密/解密
            X509EncodedKeySpec类(java.security.spec.X509EncodedKeySpec)
                此类表示根据 ASN.1 类型 SubjectPublicKeyInfo 进行编码的公用密钥的 ASN.1 编码
                获得实例
                    X509EncodedKeySpec(byte[] encodedKey) 
                        根据给定的编码密钥创建一个新的 X509EncodedKeySpec。
            PKCS8EncodedKeySpec类(java.security.spec.PKCS8EncodedKeySpec)
                此类表示按照 ASN.1 类型 PrivateKeyInfo 进行编码的专用密钥的 ASN.1 编码
                获得实例
                    PKCS8EncodedKeySpec(byte[] encodedKey) 
                        根据给定的编码密钥创建一个新的 PKCS8EncodedKeySpec。
            KeyFactory类(java.security.KeyFactory)
                密钥工厂 可将两种兼容的密钥规范进行相互转换,即转换密钥类型
                获得实例
                    static KeyFactory getInstance(String algorithm) 
                        生成实现指定算法的 KeyFactory 对象。 
                常用方法
                    String getAlgorithm() 
                        获取与此 KeyFactory 相关联的算法的名称。 
                    PrivateKey generatePrivate(KeySpec keySpec) 
                        根据所提供的密钥规范(密钥材料)生成私钥对象。 
                    PublicKey generatePublic(KeySpec keySpec) 
                        根据所提供的密钥规范(密钥材料)生成公钥对象。 
            Cipher类参见对称加密
        数字签名
            发送报文时,发送方用一个哈希函数从报文文本中生成报文摘要,然后用自己的私人密钥对这个摘要进行加密,这个加密后的摘要将作为报文的数字签名和报文一起发送给接收方
            接收方首先用与发送方一样的哈希函数从接收到的原始报文中计算出报文摘要,接着再用发送方的公用密钥来对报文附加的数字签名进行解密,如果这两个摘要相同、那么接收方就能确认该数字签名是发送方的
            Signature类(java.security.Signature)
                此类用来为应用程序提供数字签名算法功能。数字签名用来保证数字数据的真实性和完整性。
                获得实例
                    static Signature getInstance(String algorithm) 
                        生成实现指定摘要算法的 Signature 对象。 
                        algorithm的值可以为: MD5withRSA 和 SHA1withRSA
                常用方法
                    void initSign(PrivateKey privateKey) 
                        初始化此用于签名的对象。 
                    void initVerify(PublicKey publicKey) 
                        初始化此用于验证的对象。 
                    void update(byte[] data) 
                        使用指定的字节数组更新要签名或验证的数据。
                    byte[] sign() 
                        返回所有已更新数据的签名字节。 
                    boolean verify(byte[] signature) 
                        验证传入的签名。 
        RSA
            /**
             * 生成私钥和公钥
             * @return
             * @throws Exception
             */
            public static Map<String, String> createPublicAndPrivateKey() throws Exception {
                KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
                keyPairGen.initialize(1024);//RSA模长,太大影响加密效率,太小不安全.要加密的数据最大长度为 模长/8-11 ,如果数据过长,要分段加密
                KeyPair keyPair = keyPairGen.generateKeyPair();
                Map<String, String> map = new HashMap<String, String>();
                map.put("publicKey", Base64Utils.encode(keyPair.getPublic().getEncoded()));
                map.put("privateKey", Base64Utils.encode(keyPair.getPrivate().getEncoded()));
                return map;
            }
            
            /**
             * 获得公钥或私钥对象
             * @param keystr
             * @return
             */
            private static Key getKey(String keystr){
                try {
                    Key key = null;
                    byte[] keyBytes = Base64Utils.decode(keystr);
                    //获得密钥工厂类(KeyFactory)
                    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                    if(keystr.length()==216){               //获得公钥,模长为1024则公钥长度为216
                        //获得X509EncodedKeySpec对象
                        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
                        //将X509EncodedKeySpec对象转换为 公钥
                        key = keyFactory.generatePublic(x509KeySpec);
                    }else if(keystr.length()==848){         //获得私钥,模长为1024则公钥长度为848
                        //获得PKCS8EncodedKeySpec对象
                        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
                        //将PKCS8EncodedKeySpec对象转换为 私钥
                        key = keyFactory.generatePrivate(pkcs8KeySpec);
                    }
                    return key;
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
            
            /**
             * 加密或解密
             * @param datastr
             * @param isPublicKey
             * @param isEncrypt
             * @return
             */
            private static String cipher(String datastr,String keystr,boolean isEncrypt){
                try {
                    int mode = -1; //加密类型
                    byte[] dataByte = null; //数据字节数组
                    int blackSize = -1; //数据分块大小
                    if(isEncrypt){
                        mode = Cipher.ENCRYPT_MODE;
                        dataByte = datastr.getBytes("utf-8");
                        blackSize = 1024/8-11;
                    }else{
                        mode = Cipher.DECRYPT_MODE;
                        dataByte = Base64Utils.decode(datastr);
                        blackSize = 1024/8;
                    }
                    Key key = getKey(keystr);//生成公钥或私钥
                    
                    //获得 密码生成器
                    Cipher cipher = Cipher.getInstance("RSA");
                    cipher.init(mode, key);
                    
                    //分段加密/解密
                    //(要加密的数据最大长度为 模长/8-11 ,模长在生成公钥和私钥时指定, 这里为1024, 所以数据长度不能超过117)
                    //(要解密的数据最大长度为 模长/8 ,模长在生成公钥和私钥时指定, 这里为1024, 所以数据长度不能超过128)
                    ByteArrayOutputStream out = new ByteArrayOutputStream();
                    int count = dataByte.length/blackSize;
                    for(int i=0;i<count;i++){
                        out.write(cipher.doFinal(dataByte,blackSize*i,blackSize));
                    }
                    int yu = dataByte.length % blackSize;
                    if(yu!=0){
                        out.write(cipher.doFinal(dataByte,blackSize*count,yu));
                    }
                    dataByte = out.toByteArray();
                    out.close();
                    
                    if(isEncrypt){
                        datastr = Base64Utils.encode(dataByte);
                    }else{
                        datastr = new String(dataByte,"utf-8");
                    }
                    return datastr;
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
            
            /**
             * 使用公钥加密
             * @param datastr
             * @param publicKey
             * @return
             * @throws Exception
             */
            public static String encryptByPublicKey(String datastr, String publicKey)
                    throws Exception {
                return cipher(datastr,publicKey,true);
            }
            
            /**
             * 使用私钥加密
             * @param datastr
             * @param privateKey
             * @return
             * @throws Exception
             */
            public static String encryptByPrivateKey(String datastr, String privateKey)
                    throws Exception {
                return cipher(datastr,privateKey,true);
            }
            
            /**
             * 使用公钥解密
             * @param datastr
             * @param publicKey
             * @return
             * @throws Exception
             */
            public static String decryptByPublicKey(String datastr, String publicKey)
                    throws Exception {
                return cipher(datastr,publicKey,false);
            }
            
            /**
             * 使用私钥解密
             * @param datastr
             * @param privateKey
             * @return
             * @throws Exception
             */
            public static String decryptByPrivateKey(String datastr, String privateKey)
                    throws Exception {
                return cipher(datastr,privateKey,false);
            }
            
            /**
             * 获得数字签名
             * @param datastr 要进行签名的数据
             * @param privateKey
             * @return
             */
            public static String sign(String datastr, String privateKey){
                try {
                    byte[] dataByte = Base64Utils.decode(datastr);
                    Key key = getKey(privateKey);
                    
                    Signature signature = Signature.getInstance("MD5withRSA");
                    signature.initSign((PrivateKey) key);//初始化
                    signature.update(dataByte);//更新要前面的数据
                    return Base64Utils.encode(signature.sign());//签名
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
            
            /**
             * 验证数字签名
             * @param datastr
             * @param signstr
             * @param publicKey
             * @return
             */
            public static boolean verifySign(String datastr,String signstr,String publicKey){
                try {
                    byte[] dataByte = Base64Utils.decode(datastr);
                    byte[] signByte = Base64Utils.decode(signstr);
                    Key key = getKey(publicKey);
                    
                    Signature signature = Signature.getInstance("MD5withRSA");
                    signature.initVerify((PublicKey) key);//初始化
                    signature.update(dataByte);//更新要前面的数据
                    return signature.verify(signByte);//验签
                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
            }
        在网上的第二种加密方式(与上面的加密方式结果不同)(了解就好)
            这个没有将key保存为字符串,而是保存到文件,实现类不一样
            需要用到一个jar包bcprov-jdk15-1.45.jar
            代码
                /**
                 * RSA 工具类。提供加密,解密,生成密钥对等方法。
                 * 需要到http://www.bouncycastle.org下载bcprov-jdk14-123.jar。
                 * 
                 */
                public class RSAUtil {
                    
                    /**
                     * 加密算法RSA
                     */
                    public static final String KEY_ALGORITHM = "RSA";
                     /**
                     * RSA最大加密明文大小
                     */
                    private static final int MAX_ENCRYPT_BLOCK = 117;
                    /**
                     * RSA最大解密密文大小
                     */
                    private static final int MAX_DECRYPT_BLOCK = 128;
                    
                    
                    /**
                     * @描述:生成密钥对
                     * @开发人员:
                     * @开发时间:2015年7月24日 上午08:00:00
                     */
                    public static KeyPair generateKeyPair() throws Exception {
                        try {
                            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA",
                                    new org.bouncycastle.jce.provider.BouncyCastleProvider());
                            final int KEY_SIZE = 1024;// 没什么好说的了,这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会低
                            keyPairGen.initialize(KEY_SIZE, new SecureRandom());
                            KeyPair keyPair = keyPairGen.generateKeyPair();
                            saveKeyPair(keyPair);
                            return keyPair;
                        } catch (Exception e) {
                            throw new Exception(e.getMessage());
                        }
                    }
                    
                    /**
                     * @描述:从本地文件读取密钥对
                     * @开发人员:
                     * @开发时间:2015年7月24日 上午08:00:00
                     */
                    public static KeyPair getKeyPair()throws Exception{
                        try{
                            FileInputStream fis = new FileInputStream("F:\\_workspace\\sss\\src\\RSAKey.txt");
                             ObjectInputStream oos = new ObjectInputStream(fis);
                             KeyPair kp= (KeyPair) oos.readObject();
                             oos.close();
                             fis.close();
                             return kp;
                        }catch(Exception e){
                            throw new Exception("ERROR.UTIL.GET_KEYPARI_ERROR",e);
                        }
                        
                    }
                    
                    /**
                     * @描述:保存密钥对到本地文件
                     * @开发人员:
                     * @开发时间:2015年7月24日 上午08:00:00
                     * @params kp 要保存的密钥对
                     */
                    public static void saveKeyPair(KeyPair kp)throws Exception{
                        
                         FileOutputStream fos = new FileOutputStream("F:\\_workspace\\sss\\src\\RSAKey.txt");
                         ObjectOutputStream oos = new ObjectOutputStream(fos);
                         //生成密钥
                         oos.writeObject(kp);
                         oos.close();
                         fos.close();
                    }
                    
                    /**
                     * @描述:生成公钥
                     * @开发人员:
                     * @开发时间:2015年7月24日 上午08:00:00
                     * @param modulus *
                     * @param publicExponent *
                     * @return RSAPublicKey *
                     * @throws Exception
                     */
                    public static RSAPublicKey generateRSAPublicKey(byte[] modulus,
                            byte[] publicExponent) throws Exception {
                        KeyFactory keyFac = null;
                        try {
                            keyFac = KeyFactory.getInstance("RSA",
                                    new org.bouncycastle.jce.provider.BouncyCastleProvider());
                        } catch (NoSuchAlgorithmException ex) {
                            throw new Exception(ex.getMessage());
                        }

                        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
                                modulus), new BigInteger(publicExponent));
                        try {
                            return (RSAPublicKey) keyFac.generatePublic(pubKeySpec);
                        } catch (InvalidKeySpecException ex) {
                            throw new Exception(ex.getMessage());
                        }
                    }

                    /**
                     * @描述:生成私钥
                     * @开发人员:
                     * @开发时间:2015年7月24日 上午08:00:00
                     * @param modulus *
                     * @param privateExponent *
                     * @return RSAPrivateKey *
                     * @throws Exception
                     */
                    public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus,
                            byte[] privateExponent) throws Exception {
                        KeyFactory keyFac = null;
                        try {
                            keyFac = KeyFactory.getInstance("RSA",
                                    new org.bouncycastle.jce.provider.BouncyCastleProvider());
                        } catch (NoSuchAlgorithmException ex) {
                            throw new Exception(ex.getMessage());
                        }

                        RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(
                                modulus), new BigInteger(privateExponent));
                        try {
                            return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec);
                        } catch (InvalidKeySpecException ex) {
                            throw new Exception(ex.getMessage());
                        }
                    }

                    /**
                     * @描述:加密
                     * @开发人员:
                     * @开发时间:2015年7月24日 上午08:00:00
                     * @param key  加密的密钥 *
                     * @param data 待加密的明文数据 *
                     * @return 加密后的数据 *
                     * @throws Exception
                     */
                    public static byte[] encrypt(PublicKey pk, byte[] data) throws Exception {
                        try {
                            Cipher cipher = Cipher.getInstance("RSA",
                                    new org.bouncycastle.jce.provider.BouncyCastleProvider());
                            cipher.init(Cipher.ENCRYPT_MODE, pk);
                            int blockSize = cipher.getBlockSize();// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024
                            // 加密块大小为127
                            // byte,加密后为128个byte;因此共有2个加密块,第一个127
                            // byte第二个为1个byte
                            int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小
                            int leavedSize = data.length % blockSize;
                            int blocksSize = leavedSize != 0 ? data.length / blockSize + 1
                                    : data.length / blockSize;
                            byte[] raw = new byte[outputSize * blocksSize];
                            int i = 0;
                            while (data.length - i * blockSize > 0) {
                                if (data.length - i * blockSize > blockSize)
                                    cipher.doFinal(data, i * blockSize, blockSize, raw, i
                                            * outputSize);
                                else
                                    cipher.doFinal(data, i * blockSize, data.length - i
                                            * blockSize, raw, i * outputSize);
                                // 这里面doUpdate方法不可用,查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到
                                // ByteArrayOutputStream中,而最后doFinal的时候才将所有的byte[]进行加密,可是到了此时加密块大小很可能已经超出了
                                // OutputSize所以只好用dofinal方法。

                                i++;
                            }
                            return raw;
                        } catch (Exception e) {
                            throw new Exception(e.getMessage());
                        }
                    }

                    /**
                     * @描述:解密
                     * @开发人员:
                     * @开发时间:2015年7月24日 上午08:00:00
                     * @param key 解密的密钥 *
                     * @param raw 已经加密的数据 *
                     * @return 解密后的明文 
                     * @throws Exception
                     */
                    public static byte[] decrypt(PrivateKey pk, byte[] raw) throws Exception  {
                        try {
                            Cipher cipher = Cipher.getInstance("RSA",
                                    new org.bouncycastle.jce.provider.BouncyCastleProvider());
                            cipher.init(Cipher.DECRYPT_MODE, pk);
                            int blockSize = cipher.getBlockSize();
                            ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
                            int j = 0;

                            while (raw.length - j * blockSize > 0) {
                                bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
                                j++;
                            }
                            return bout.toByteArray();
                        } catch (Exception e) {
                            throw new Exception("ERROR.UTIL.SRA_DECRYPT_ERROR",e);
                        }
                    }
                    
                    /**
                     * @描述:根据modulus,public exponent得到PublicKey
                     * @开发人员:
                     * @开发时间:2015年7月24日 上午08:00:00
                     * @param modulus 十进制的modulus串
                     * @param publicExponent 十进制的publicExponent串
                     * @return PublicKey类型的公钥
                     * @throws Exception
                     */
                    public static PublicKey getPublicKey(String modulus, String publicExponent) throws Exception {
                        //将字符串转换为BigInteger类型
                        BigInteger modulusBigInt = new BigInteger(modulus, 16);
                        BigInteger publicExponentBigInt = new BigInteger(publicExponent, 16);

                        KeySpec publicKeySpec = new RSAPublicKeySpec(modulusBigInt, publicExponentBigInt);
                        KeyFactory factory = KeyFactory.getInstance("RSA");
                        PublicKey publicKey = factory.generatePublic(publicKeySpec);
                        return publicKey;
                    }
                    
                    /**
                     * @描述:根据modulus,private exponent得到PrivateKey
                     * @开发人员:
                     * @开发时间:2015年7月24日 上午08:00:00
                     * @param modulus 十进制的modulus串
                     * @param privateExponent 十进制的privateExponent串
                     * @return PrivateKey类型的公钥
                     * @throws Exception
                     */
                    public static PrivateKey getPrivateKey(String modulus, String privateExponent) throws Exception {
                        //将字符串转换为BigInteger类型
                        BigInteger modulusBigInt = new BigInteger(modulus, 16);
                        BigInteger privateExponentBigInt = new BigInteger(privateExponent, 16);

                        KeySpec privateKeySpec = new RSAPrivateKeySpec(modulusBigInt, privateExponentBigInt);
                        KeyFactory factory = KeyFactory.getInstance("RSA");
                        PrivateKey privateKey = factory.generatePrivate(privateKeySpec);
                        return privateKey;
                    }
                    
                    /**
                     * <p>
                     * 私钥加密
                     * </p>
                     * 
                     * @param data 源数据
                     * @param privateKey 私钥(BASE64编码)
                     * @return
                     * @throws Exception
                     */
                    public static String encryptByPrivateKey(String datastr, String privateKey)
                            throws Exception {
                        byte[] data = datastr.getBytes();
                        byte[] keyBytes = AlgorithmUtils.decodeBase64(privateKey);
                //        byte[] keyBytes = Base64Utils.decode(privateKey);
                        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
                        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
                        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
                        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
                        cipher.init(Cipher.ENCRYPT_MODE, privateK);
                        int inputLen = data.length;
                        ByteArrayOutputStream out = new ByteArrayOutputStream();
                        int offSet = 0;
                        byte[] cache;
                        int i = 0;
                        // 对数据分段加密
                        while (inputLen - offSet > 0) {
                            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                            } else {
                                cache = cipher.doFinal(data, offSet, inputLen - offSet);
                            }
                            out.write(cache, 0, cache.length);
                            i++;
                            offSet = i * MAX_ENCRYPT_BLOCK;
                        }
                        byte[] encryptedData = out.toByteArray();
                        out.close();
                        return AlgorithmUtils.encodeBase64(encryptedData);
                //        return Base64.encode(encryptedData);
                    }
                    
                    /**
                     * <P>
                     * 私钥解密
                     * </p>
                     * 
                     * @param encryptedData 已加密数据
                     * @param privateKey 私钥(BASE64编码)
                     * @return
                     * @throws Exception
                     */
                    public static String decryptByPrivateKey(String encrypted, String privateKey)
                            throws Exception {
                //      byte[] encryptedData = Base64.decode(encrypted);
                        byte[] encryptedData = AlgorithmUtils.decodeBase64(encrypted);
                //        byte[] keyBytes = Base64Utils.decode(privateKey);
                        byte[] keyBytes = AlgorithmUtils.decodeBase64(privateKey);
                        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
                        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
                        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
                        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
                        cipher.init(Cipher.DECRYPT_MODE, privateK);
                        int inputLen = encryptedData.length;
                        ByteArrayOutputStream out = new ByteArrayOutputStream();
                        int offSet = 0;
                        byte[] cache;
                        int i = 0;
                        // 对数据分段解密
                        while (inputLen - offSet > 0) {
                            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
                            } else {
                                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                            }
                            out.write(cache, 0, cache.length);
                            i++;
                            offSet = i * MAX_DECRYPT_BLOCK;
                        }
                        byte[] decryptedData = out.toByteArray();
                        out.close();
                        return new String(decryptedData);
                    }
                }
    对比:
        非对称加密与对称加密相比,其安全性更好:对称加密的通信双方使用相同的秘钥,如果一方的秘钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对秘钥,一个用来加密,一个用来解密,而且公钥是公开的,秘钥是自己保存的,不需要像对称加密那样在通信之前要先同步秘钥。
        非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。



注意
    前面所有的算法,都是对字节数组进行操作,使用不同编码加密结果不同,如:
    digest.digest(str.getBytes("gbk"));
    digest.digest(str.getBytes("utf-8"));



字节数组和字符串的转换
    常见转换方式有 
        new String()
        base64编码
        字节数组转换为16进制表意字符串
    base64编码
        将二进制数据编码为ASCII字符串,便于传输
        数据每3个字节变为4个字节,可解码
        sun公司提供了内置的实现,但由于MyEclipse中默认类库没有,需重新导入jre库.下面提供了自定义的实现类
        编码
            sun.misc.BASE64Encoder类
            sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
            String str = encoder.encode("要编码的字符串".getBytes());
            System.out.println(str);
        解码
            sun.misc.BASE64Decoder类
            sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
            byte[] bytes = decoder.decodeBuffer("要解码的字符串");
            System.out.println(bytes);
        注意
            myeclipse默认的类库没有上面两个类,换个jre库就好了
            项目右键-->Properties-->Java Build Path-->Libraries-->删除原来的-->Add Library-->JRE System Library
        自定义Base64加密
            private static char[] base64EncodeChars = new char[] { 'A', 'B', 'C', 'D',
                'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
                'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
                'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
                'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
                '4', '5', '6', '7', '8', '9', '+', '/' };
            private static byte[] base64DecodeChars = new byte[] { -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59,
                60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1,
                -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
                38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1,
                -1, -1 };
            /**
             * base64编码
             * @param data
             * @return
             */
            public static String encodeBase64(byte[] data) {
                StringBuffer sb = new StringBuffer();
                int len = data.length;
                int i = 0;
                int b1, b2, b3;
                while (i < len) {
                    b1 = data[i++] & 0xff;
                    if (i == len) {
                        sb.append(base64EncodeChars[b1 >>> 2]);
                        sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
                        sb.append("==");
                        break;
                    }
                    b2 = data[i++] & 0xff;
                    if (i == len) {
                        sb.append(base64EncodeChars[b1 >>> 2]);
                        sb.append(base64EncodeChars[((b1 & 0x03) << 4)
                                | ((b2 & 0xf0) >>> 4)]);
                        sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
                        sb.append("=");
                        break;
                    }
                    b3 = data[i++] & 0xff;
                    sb.append(base64EncodeChars[b1 >>> 2]);
                    sb.append(base64EncodeChars[((b1 & 0x03) << 4)
                            | ((b2 & 0xf0) >>> 4)]);
                    sb.append(base64EncodeChars[((b2 & 0x0f) << 2)
                            | ((b3 & 0xc0) >>> 6)]);
                    sb.append(base64EncodeChars[b3 & 0x3f]);
                }
                return sb.toString();
            }

            /**
             * base64解码
             * @param str
             * @return
             */
            public static byte[] decodeBase64(String str){
                try {
                    StringBuffer sb = new StringBuffer();
                    byte[] data = str.getBytes("US-ASCII");
                    int len = data.length;
                    int i = 0;
                    int b1, b2, b3, b4;
                    while (i < len) {
                        do {
                            b1 = base64DecodeChars[data[i++]];
                        } while (i < len && b1 == -1);
                        if (b1 == -1)
                            break;

                        do {
                            b2 = base64DecodeChars[data[i++]];
                        } while (i < len && b2 == -1);
                        if (b2 == -1)
                            break;
                        sb.append((char) ((b1 << 2) | ((b2 & 0x30) >>> 4)));

                        do {
                            b3 = data[i++];
                            if (b3 == 61)
                                return sb.toString().getBytes("iso8859-1");
                            b3 = base64DecodeChars[b3];
                        } while (i < len && b3 == -1);
                        if (b3 == -1)
                            break;
                        sb.append((char) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));

                        do {
                            b4 = data[i++];
                            if (b4 == 61)
                                return sb.toString().getBytes("iso8859-1");
                            b4 = base64DecodeChars[b4];
                        } while (i < len && b4 == -1);
                        if (b4 == -1)
                            break;
                        sb.append((char) (((b3 & 0x03) << 6) | b4));
                    }
                    return sb.toString().getBytes("iso8859-1");
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
    转换为16进制表意字符串
        /**
         * 将字节数组转换为16进制字符串形式(字节-->表意字节字符串,16进制每个字节显示为固定2位字符,可将字节数组显示为字符串)
         * @param bytes
         * @return
         */
        public static String byteToHexStr(byte[] bytes) {
            if (bytes == null){
                return null;
            }
            StringBuffer output = new StringBuffer(bytes.length * 2);
            for (int i = 0; i < bytes.length; i++) {
                int current = bytes[i] & 0xff;
                if (current < 16){
                    output.append("0");
                }
                output.append(Integer.toString(current, 16));
            }
            return output.toString();
        }
        
        /**将16进制字符串转换为字节数组(表意字节字符串-->字节数组,16进制固定2个字符转换为一个字节)
         * @param hexStr
         * @return 经字节数组编码可得到原始字符串
         */
        public static byte[] hexStrToByte(String hexStr) {
            if (hexStr.length() < 1){
                return null;
            }
            byte[] result = new byte[hexStr.length()/2];
            for (int i = 0;i< hexStr.length()/2; i++) {
                int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
                int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
                result[i] = (byte) (high * 16 + low);
            }
            return result;
        }







  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

qq1123734918

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值