安全之加密算法(-)

**目前各种系统,特别是政府和金融领域的系统对于系统的安全都是特别重视的,提到安全,不得不提加密算法,提到加密算法不得不提的两种加密类型:
对称加密和非对称加密**
抄下百度吧:

对称加密:

需要对加密和解密使用相同密钥的加密算法。由于其速度快,对称性加密通常在消息发送方需要加密大量数据时使用。对称性加密也称为密钥加密。
所谓对称,就是采用这种加密方法的双方使用方式用同样的密钥进行加密和解密。密钥是控制加密及解密过程的指令。算法是一组规则,规定如何进行加密和解密。
因此[1] 加密的安全性不仅取决于加密算法本身,密钥管理的安全性更是重要。因为加密和解密都使用同一个密钥,如何把密钥安全地传递到解密者手上就成了必须要解决的问题。

非对称加密:

1976年,美国学者Dime和Henman为解决信息公开传送和密钥管理问题,提出一种新的密钥交换协议,允许在不安全的媒体上的通讯双方交换信息,安全地达成一致的密钥,这就是“公开密钥系统”。
与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

数字签名:

数字签名(又称公钥数字签名、电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。
数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。
数字签名是非对称密钥加密技术与数字摘要技术的应用。

总结:
对称加密是指加密和解密采用相同或者相似的秘钥,常用的有:des,aes,三重des

非对称加密是指加密和解密采用不同的秘钥,加密的叫做公钥,解密的叫做私钥,公钥是可以公开的,其实这么说也不完全对,非对称加密是成对出现的,任何一方都可以用作加密也都可以公开,公开的一方即是公钥,不公开的一方即是私钥.
不过一般公钥加密,私钥解密用作加密
私钥加密,公钥解密用作签名

从公钥无法推算出私钥,同理反过来也是如此.
常用有rsa(其实我就知道这一个)

优缺点:
对称加密较快,但是相对安全性较弱,,一般适用于数据量较大.秘钥的保存是个问题,如果完全依赖于用户本身,是不可靠的,任何系统考虑系统安全性时,都应将用户的可靠性置于极低的位置.

非对称加密,算法复杂,速度较慢,安全性较高,适用于较少数据量.

所以一般系统数据量较大时,一般采用:对称加密数据信息,非对称加密对称秘钥.

java中应用介绍:

对于这些公开的加密算法,java底层都有用c或c++实现,jni调用即可,所以我们在java中使用这些算法时,不需要繁琐的操作

java中aes对称加密实现

package com.taoyuan.demo;


import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


import com.taoyuan.demo.ByteUtil.StringType;
public class AesUtil {
    public static final String DEFAULT_AES_TYPE="AES/CBC/PKCS5Padding";
    public static final byte[] DEFAULT_AES_IV="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".getBytes();//指定默认偏移量
    public static final StringType STRING_TYPE=StringType.BASE64;
    /**加密二进制,这种初始化对称秘钥方式,可以实现php和java的互通,根据password的位数16位 128 32位 256区别加密位数
     * @param data
     * @param password
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data,String password) throws Exception{
        Cipher cipher = Cipher.getInstance(DEFAULT_AES_TYPE);// 创建密码器(采用padding方式,解决明文长度不为16的倍数问题)
        cipher.init(Cipher.ENCRYPT_MODE, getKey1(password),new IvParameterSpec(DEFAULT_AES_IV) );// 初始化
        byte[] result = cipher.doFinal(data);
        return result;// 加密 
    }

    /**解密二进制
     * @param data
     * @param password
     * @retu
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data,String password) throws Exception{
        Cipher cipher = Cipher.getInstance(DEFAULT_AES_TYPE);// 创建密码器(采用padding方式,解决明文长度不为16的倍数问题)
        cipher.init(Cipher.DECRYPT_MODE, getKey1(password), new IvParameterSpec(DEFAULT_AES_IV) );// 初始化
        byte[] result = cipher.doFinal(data);
        return result;
    }
/*  默认加密模式:AES/CBC/PKCS5Padding(此种方式的加密数据无法满足跨平台的需求,应为秘钥的生成是根据密码加随机数,
             *其他平台无法或者很难重现这种过程)*/
    /**
     * 加密
     * 
     * @param content
     *            需要加密二进制内容
     * @param password
     *            加密密码
     * @return
     */
    public static  byte[] encryptJava(byte[] content,String password) {
        try {
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            cipher.init(Cipher.ENCRYPT_MODE, getKey(password));// 初始化
            byte[] result = cipher.doFinal(content);
            return result; // 加密
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 解密
     * 
     * @param content
     *            解密二进制
     * @param password
     *            解密密钥
     * @return
     */
    public static byte[] decryptJava(byte[] content,String password) {
        try {
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            cipher.init(Cipher.DECRYPT_MODE, getKey(password));// 初始化
            byte[] result = cipher.doFinal(content);
            return result; // 加密
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //加解密字符串

    public static String encrypt(String data,String password) throws Exception{
        return ByteUtil.byteToString(encrypt(data.getBytes(), password),STRING_TYPE);
    }
    public static String decrypt(String data,String password) throws Exception{
        return new String(decrypt(ByteUtil.stringToByte(data, STRING_TYPE), password));
    }

    public static String encryptJava(String data,String password) throws Exception{
        return ByteUtil.byteToString(encryptJava(data.getBytes(), password),STRING_TYPE);
    }
    public static String decryptJava(String data,String password) throws Exception{
        return new String(decryptJava(ByteUtil.stringToByte(data, STRING_TYPE), password));
    }


    //这种初始化密码方式,不跨平台,只在java语言使用,安全性较高
    public static SecretKey getKey(String password) throws Exception{
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        //解决linux异常
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );  
        secureRandom.setSeed(password.getBytes()); 
        kgen.init(256, secureRandom);
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
        return key;
    }
    //直接使用密码作为对称秘钥,跨平台
    public static SecretKey getKey1(String password){
        return new SecretKeySpec(password.getBytes(), "AES");//创建aes格式的密码
    }

}

php中aes加密实现,可以与上面的aes加密实现互通

<?php

namespace common\lib\aes;
/**
 * @method encrypt AES加密算法 其中padding为pkcs5padding算法
 * @method decrypt AES解密算法
 * @method substr 字符串截取
 */
class AES
{

    /**
     * @TODO AES加密
     * @param $string the string to encrypt
     * @param $key the key for encrypt 128位加密 传16为key 256位加密传32位key
     * @param $iv the iv for encrypt 128位加密 传16为iv 256位加密传32位iv
     * @param $algorithm AES length mode(MCRYPT_RIJNDAEL_128,MCRYPT_RIJNDAEL_192,MCRYPT_RIJNDAEL_256)
     * @param $mode AES encrypt (such as MCRYPT_MODE_CBC,MCRYPT_MODE_ECB..)
     * @param $padding need or not to padding
     * @return string
     */
    static public function encrypt($string, $key=null, $iv = null , $algorithm = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_CBC, $padding = true, $base64 = true)
    {
        if(!is_string($string) or empty($string)) return '';
        if(!extension_loaded('mcrypt')) throw new \Exception('AesEncrypt requires PHP mcrypt extension to be loaded in order to use data encryption feature.');

        //mcrypt init
        $module = mcrypt_module_open($algorithm, '', $mode, '');

        if(is_null($iv)){
            //偏移量为0
            $iv = str_repeat("\0", 16);
        }

        mcrypt_generic_init($module, $key, $iv);

        if($padding){
            $block = mcrypt_get_block_size($algorithm, $mode);
            $pad = $block - (strlen($string) % $block); //Compute how many characters need to pad
            $string .= str_repeat(chr($pad), $pad);  // After pad, the str length must be equal to block or its integer multiples
        }

        //encrypt
        $encrypted = mcrypt_generic($module, $string);

        //Close
        mcrypt_generic_deinit($module);
        mcrypt_module_close($module);
        return $base64 ? base64_encode($encrypted) : $encrypted;
    }

    /**
     * @TODO AES解密
     * @param $string the string to decrypt
     * @param $key the key for decrypt 128位加密 传16为key 256位加密传32位key
     * @param $iv the iv for decrypt 128位加密 传16为iv 256位加密传32位iv
     * @param $algorithm AES length mode(MCRYPT_RIJNDAEL_128,MCRYPT_RIJNDAEL_192,MCRYPT_RIJNDAEL_256)
     * @param $mode AES decrypt (such as MCRYPT_MODE_CBC,MCRYPT_MODE_ECB..)
     * @param $padding need or not to padding
     * @return string
     */
    static public function decrypt($encryptString, $key = null, $iv = null, $algorithm = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_CBC)
    {

        if(!is_string($encryptString) or empty($encryptString)) return '';

        $encryptString = base64_decode($encryptString);

        if(!extension_loaded('mcrypt')) throw new \Exception('AesEncrypt requires PHP mcrypt extension to be loaded in order to use data encryption feature.');

        $module = mcrypt_module_open($algorithm, '', $mode, '');

        if(is_null($iv))
        {
            $iv = str_repeat("\0",16);
        }
        mcrypt_generic_init($module, $key, $iv);

        /* Decrypt encrypted string */
        $decrypted = mdecrypt_generic($module, $encryptString);

        /* Terminate decryption handle and close module */
        mcrypt_generic_deinit($module);
        mcrypt_module_close($module);

        return rtrim($decrypted, "\0");
    }
}

java中rsa非对称加密,签名验签实现

package com.taoyuan.demo;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Enumeration;
import java.util.Properties;
import javax.crypto.Cipher;
import com.taoyuan.demo.support.SupportUtil;

public class RSAUtil {
      public static final String CERT_TYPE_P12 = "PKCS12";

        public static final String ENCRYPT_TYPE_RSA = "RSA";
        public static final String DEFAILT_ALGORITHM = "MD5withRSA";//MD5withRSA,SHA1WithRSA,SHA256WithRSA,SHA384WithRSA
        public static final String CERT_TYPE_X509 = "X.509";
        public static final String DEFAULT_CER = "server.cer";//默认通信方公钥
        public static final String DEFAULT_CLIENT_P12 = "client.p12";//客户端证书
        public static KeyStore keyStore;
        public static String keyPassword;
        static{
            try {
                Properties pro=new Properties();
                InputStream resourceAsStream = RSAUtil.class.getClassLoader().getResourceAsStream("config.properties");
                pro.load(resourceAsStream);
                keyStore = KeyStore.getInstance(CERT_TYPE_P12);
                InputStream input=null;
                String certPath=pro.getProperty("p12Path");
                File certFile=new File(certPath);
                if(SupportUtil.isEmpty(certPath)||!certFile.exists()){
                    input=RSAUtil.class.getClassLoader().getResourceAsStream(DEFAULT_CLIENT_P12);
                }else{
                    input=new FileInputStream(certPath);
                }
                keyPassword=pro.getProperty("certPWD");
                keyStore.load(input, keyPassword.toCharArray());
            } catch (Exception e) {
                e.printStackTrace();
              System.err.print("加载p12证书失败\n"+e);
            }
        }
         private static RSAPublicKey getPublicKey() throws Exception {
            String key_aliases = null;
            Enumeration<String> enumeration = keyStore.aliases();
            key_aliases = enumeration.nextElement();
            if (keyStore.isKeyEntry(key_aliases)) {
                RSAPublicKey publicKey = (RSAPublicKey) keyStore.getCertificate(key_aliases).getPublicKey();
                return publicKey;
            }
            return null;
        }
        private static RSAPrivateKey getPrivateKey() throws Exception {
            String key_aliases = null;
            Enumeration<String> enumeration = keyStore.aliases();
            key_aliases = enumeration.nextElement();
            if (keyStore.isKeyEntry(key_aliases)) {
                RSAPrivateKey privateKey = (RSAPrivateKey) keyStore.getKey(key_aliases, keyPassword.toCharArray());
                return privateKey;
            }
            return null;
        }
        /**
         * 公钥加密
         * 
         * @param data
         * @param publicKey
         * @return
         * @throws Exception
         */
        public static byte[] encryptByPublicKey(byte[] data)
                throws Exception {
         RSAPublicKey publicKey=getPublicKey();
            Cipher cipher = Cipher.getInstance(ENCRYPT_TYPE_RSA);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            // 模长
            int key_len = publicKey.getModulus().bitLength() / 8;
            // 加密数据长度 <= 模长-11,如果明文长度大于模长-11则要分组加密
            key_len-=11;
            //分组加密
            ByteArrayOutputStream out=new ByteArrayOutputStream();
            for (int i = 0; i < data.length; i += key_len) {
                byte[] doFinal = cipher.doFinal(SupportUtil.subarray(data, i, i + key_len));
                out.write(doFinal);
            }
            return out.toByteArray();
        }




        /**
         * 私钥解密
         * 
         * @param data
         * @param privateKey
         * @return
         * @throws Exception
         */
        public static byte[] decryptByPrivateKey(byte[] data)
                throws Exception {
             RSAPrivateKey privateKey=getPrivateKey();
            Cipher cipher = Cipher.getInstance(ENCRYPT_TYPE_RSA);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            //模长
            int key_len = privateKey.getModulus().bitLength() / 8;
            //分组解密
            ByteArrayOutputStream out=new ByteArrayOutputStream();
            //如果密文长度大于模长则要分组解密
              for (int i = 0; i < data.length; i+=key_len) {
                    byte[] doFinal = cipher.doFinal(SupportUtil.subarray(data, i, i+key_len));
                    out.write(doFinal);
           }

              return out.toByteArray();
    }
            //验证签名数据
            public static boolean vefySign(byte[] content,byte[] signvalue,PublicKey  publicKey){
                try {
                    if(publicKey==null)publicKey=getPublicKey();
                    Signature signature = Signature.getInstance(DEFAILT_ALGORITHM);
                    signature.initVerify(publicKey);
                    signature.update(content);
                    boolean bverify = signature.verify(signvalue);
                    return bverify;
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return false;

            }
          //签名数据
            public static byte[] signData(byte[] data) throws Exception{
                PrivateKey privateKey = getPrivateKey();
                Signature signture = Signature.getInstance(DEFAILT_ALGORITHM);
                signture.initSign(privateKey);
                signture.update(data);
                return signture.sign();
            }
            //使用外部的key加密
            public static byte[] encryptByPublicKey(byte[] data,String publicKeyPath)
                    throws Exception {
                RSAPublicKey rsaPublicKey=(RSAPublicKey)getPublicKeyCer(publicKeyPath);
                Cipher cipher = Cipher.getInstance(ENCRYPT_TYPE_RSA);
                cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
                // 模长
                int key_len = rsaPublicKey.getModulus().bitLength() / 8;
                // 加密数据长度 <= 模长-11,如果明文长度大于模长-11则要分组加密
                key_len-=11;
                //分组加密
                ByteArrayOutputStream out=new ByteArrayOutputStream();
                for (int i = 0; i < data.length; i += key_len) {
                    byte[] doFinal = cipher.doFinal(SupportUtil.subarray(data, i, i + key_len));
                    out.write(doFinal);
                }
                return out.toByteArray();
            }
            //从cer证书读取公钥
            public static PublicKey getPublicKeyCer(String cerPath) throws Exception {
                CertificateFactory certificatefactory=CertificateFactory.getInstance(CERT_TYPE_X509);
                InputStream bais=null;
                 if(SupportUtil.isEmpty(cerPath)){
                     bais = RSAUtil.class.getClassLoader().getResourceAsStream(DEFAULT_CER);
                 }else{
                     bais=new FileInputStream(cerPath);
                 }
                 X509Certificate Cert = (X509Certificate)certificatefactory.generateCertificate(bais);
                 PublicKey publicKey = Cert.getPublicKey();
                return publicKey;
            }



}

辅助工具类和包
使用了 commons-codec-1.10
字节数组转字符串,便于网络传输,目前支持三种,base64,hex,ascii

//类型枚举
package com.taoyuan.demo;

/**
 * @author 桃源 字节数组转字符
 *2017年10月6日 下午8:21:24
 */
public enum StringType {
        BASE64,HEX,ASCII;
}

//转换实现

package com.taoyuan.demo;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.BinaryCodec;
import org.apache.commons.codec.binary.Hex;


public class ByteUtil {

    public static String byteToString(byte[] data,StringType type) throws Exception{
        switch (type) {
        case BASE64:
            return Base64.encodeBase64String(data);
        case HEX:
            return Hex.encodeHexString(data);
        case ASCII:
            return BinaryCodec.toAsciiString(data);
        default:
            return Base64.encodeBase64String(data);
        }
    }
    public static byte[] stringToByte(String data,StringType type) throws Exception{
        switch (type) {
        case BASE64:
            return Base64.decodeBase64(data);
        case HEX:
            return Hex.decodeHex(data.toCharArray());
        case ASCII:
            return BinaryCodec.fromAscii(data.getBytes());
        default:
            return Base64.decodeBase64(data);
        }
    }
    public static void main(String[] args) throws Exception {
        String byteToString = byteToString("123".getBytes(),StringType.HEX );
        System.out.println(new String(stringToByte(byteToString, StringType.HEX )));
    }
}

使用测试

package com.taoyuan.demo.test;

import com.taoyuan.demo.AesUtil;
import com.taoyuan.demo.ByteUtil;
import com.taoyuan.demo.RSAUtil;
import com.taoyuan.demo.StringType;

public class Test {
    public static void main(String[] args) throws Exception {
        String data="123";
        String password="1234567812345678";
        //对称加密解密
        String en=AesUtil.encrypt(data, password);
        System.out.println(en);
        System.out.println(AesUtil.decrypt(en,password));

        String en2=AesUtil.encryptJava(data, password);
        System.out.println(en2);
        System.out.println(AesUtil.decryptJava(en2,password));


        //非对称加密解密
        String en3 = ByteUtil.byteToString(RSAUtil.encryptByPublicKey(data.getBytes()),StringType.BASE64);
        System.out.println(en3);
        System.out.println(new String(RSAUtil.decryptByPrivateKey(ByteUtil.stringToByte(en3, StringType.BASE64))));
        //签名和验签
        String signValue=ByteUtil.byteToString(RSAUtil.signData(data.getBytes()), StringType.BASE64);
        System.out.println(signValue);
        System.out.println(RSAUtil.vefySign("123".getBytes(), ByteUtil.stringToByte(signValue, StringType.BASE64), null));
    }

}

完整代码下载地址
http://download.csdn.net/download/do_bset_yourself/10009417

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值