精华内容
下载资源
问答
  • 安全算法

    千次阅读 2016-12-18 11:48:51
    常用的安全算法主要包括数字摘要、对称加密算法、非对称加密算法、信息编码等。  一、数字摘要  数字摘要也称为消息摘要,它是唯一对应一个消息或文本的固定长度的值,它由一个单向Hash函数对消息进行计算而产生。...

            安全传输除了可以使用https,还可通过安全算法实现。常用的安全算法主要包括数字摘要、对称加密算法、非对称加密算法、信息编码等。

           一、数字摘要

          数字摘要也称为消息摘要,它是唯一对应一个消息或文本的固定长度的值,它由一个单向Hash函数对消息进行计算而产生。消息在传递中改变了,接受方

    对收到的消息采用相同的Hash重新计算,产生的摘要跟原摘要进行比较,即可知道消息是否被恶意篡改了,所以消息摘要能够验证消息的完整性。常用的数字

    摘要有MD5,SHA.

          1、MD5

    MD5即Message Digest Algorithm 5,是数字摘要的一种实现,用于确保信息传输完整性和一致性,摘要长度为128位。MD5由MD4、MD3、MD2改进而来,

    主要增强了算法复杂度和不可逆性。C#的MD5算法的参考(引用msdn):

    	public static string GetMd5Hash(string input)
            {
    		MD5 md5Hash = MD5.Create();
                	// Convert the input string to a byte array and compute the hash.            
    	  	byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));            
    		// Create a new Stringbuilder to collect the bytes           
     		// and create a string.            
    		StringBuilder sBuilder = new StringBuilder();            
    		// Loop through each byte of the hashed data   
                    // and format each one as a hexadecimal string.            
    		for (int i = 0; i < data.Length; i++)            
    		{                
    			sBuilder.Append(data[i].ToString("x2"));
                    }            
    		// Return the hexadecimal string.      
    		return sBuilder.ToString();     
                    }
    	 }

     2、SHA

              SHA是全称是Secure Hash Algorithm,即安全散列算法。1993年,安全散列算法(SHA)由美国国家标准和技术协会(NIST)提出,并作为联邦

    信息处理标准(FIPS    PUB 180)公布,1995年又发布了一个修订版FIPS PUB 180-1,通常称之为SHA-1,并被广泛使用。SHA-1的摘要信息长度为

    160位,由于生成的摘要信息更长,运算的      过程更加复杂,在相同的硬件上,运算速度比MD5更慢,也更为安全。C#版SHA1算法参考

            byte[] data = new byte[DATA_SIZE];
    	byte[] result; 
    
    	SHA1 sha = new SHA1CryptoServiceProvider(); 
    	// This is one implementation of the abstract class SHA1.
    	result = sha.ComputeHash(data);  


    二、对称加密

              对称加密算法是应用较早的加密算法,加解密使用相同的密钥,对称加密过程如下所示:


    对称加密算法特点是算法公开、计算量小、加密效率高,使用长密钥时难破解性,但安全性由于依赖于密钥,泄露密钥就意味着任何人都可以对加密的

    密文进行解密,因 此密钥的保护对于加密信息是否安全至关重要。常用的对称加密算法包括DES算法、3DES算法、AES算法等。

          由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解,因此演变出了3DES算法,3DES是DES向AES过渡的加密算法。

            1、DES

                   加密算法如:

               DESCryptoServiceProvider des = new DESCryptoServiceProvider();            		
               return des.CreateEncryptor(key, key).TransformFinalBlock(plain, 0, plain.Length);
            	
                   解密算法如:
               DESCryptoServiceProvider des = new DESCryptoServiceProvider();            		
               return des.CreateDecryptor(key, key).TransformFinalBlock(encrypt, 0, encrypt.Length);
        三、非对称加密

    非对称加密算法又称为公开密钥加密算法,两个密钥,一个公钥,另一个私钥。公钥与私钥需要配对使用,如果用公钥对数据进行加密,只有对应

    的私钥才能进行解密,而 如果使用私钥对数据进行加密,那只有对应的公钥才能解密。由于加密和解密使用的是两个不同的密钥,所以这种算法称

    为非对称加密算法。具体过程如下图所示:

         


    非对称加密算法特点:对称加密算法只有一种密钥,并且是非公开的,若要解密则需要对方知道密钥,所以保证其安全性就是保证密钥的安全,而

    一旦密钥在传输过程中泄露加密信息就不再安全。而非对称加密算法包含两种密钥,其中一个是公开的,这样不需要像对称加密算法那样,需要传

    输密钥给对方进行数据加密了,大大提高了加密算法的安全性。非对称加密算法能够保证,即使在获知公钥、加密算法和加密源代码的情况下,也

    无法获知公钥对应的私钥,因此也无法对公钥加密的密文进行解密。

    由于非对称加密算法的复杂性,使得其加密解密速度远没有对称加密解密那么快,为了解决该问题,一般都是使用对称和非对称结合使用的办法,

    优缺点互补,达到时间和安全的平衡:对称加密较长的文件,然后用非对称加密算法给文件密钥加密,解决了对称加密算法密钥分发问题。

    当前使用最为广泛的非对称加密算法是RSA算法。

     


           

    展开全文
  • 常见的安全算法

    万次阅读 2017-03-28 10:00:36
    本文整理了常见的安全算法,包括MD5、SHA、DES、AES、RSA等,并写了完整的工具类(Java 版),工具类包含测试。一、数字摘要算法 数字摘要也称为消息摘要,它是一个唯一对应一个消息或文本的固定长度的值,它由一个...

    本文整理了常见的安全算法,包括MD5、SHA、DES、AES、RSA等,并写了完整的工具类(Java 版),工具类包含测试。

    一、数字摘要算法

    数字摘要也称为消息摘要,它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash函数对消息进行计算而产生。如果消息在传递的途中改变了,接收者通过对收到消息采用相同的Hash重新计算,新产生的摘要与原摘要进行比较,就可知道消息是否被篡改了,因此消息摘要能够验证消息的完整性。消息摘要采用单向Hash函数将需要计算的内容"摘要"成固定长度的串,这个串亦称为数字指纹。这个串有固定的长度,且不同的明文摘要成密文,其结果总是不同的(相对的),而同样的明文其摘要必定一致。这样这串摘要便可成为验证明文是否是"真身"的"指纹"了。

    1. Md5

    MD5即Message Digest Algorithm 5(信息摘要算法5),是数字摘要算法一种实现,用于确保信息传输完整性和一致性,摘要长度为128位。 MD5由MD4、 MD3、 MD2改进而来,主要增强算法复杂度和不可逆性,该算法因其普遍、稳定、快速的特点,在产业界得到了极为广泛的使用,目前主流的编程语言普遍都已有MD5算法实现。

    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    /**
     * Message Digest Algorithm 5(信息摘要算法5)
     */
    public class MD5Util {
    	/**
    	 * Constructs the MD5Util object and sets the string whose MD5Util is to be
    	 * computed.
    	 * 
    	 * @param inStr
    	 *    the <code>String</code> whose MD5Util is to be computed
    	 */
    	
    	
    	public final static String COMMON_KEY="zhongzhuoxin#@!321";
    	public MD5Util() {
    
    	}
    
    	public final static String str2MD5(String inStr) {
    		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    				'a', 'b', 'c', 'd', 'e', 'f' };
    		try {
    			byte[] strTemp = inStr.getBytes("UTF-8");
    			MessageDigest mdTemp = MessageDigest.getInstance("MD5");
    			mdTemp.update(strTemp);
    			byte[] md = mdTemp.digest();
    			int j = md.length;
    			char str[] = new char[j * 2];
    			int k = 0;
    			for (int i = 0; i < j; i++) {
    				byte byte0 = md[i];
    				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
    				str[k++] = hexDigits[byte0 & 0xf];
    			}
    			return new String(str);
    		} catch (Exception e) {
    			return null;
    		}
    	}
    	
    	
    	
    
    	//--MD5Util
    	private static final char HEX_DIGITS[] = { '0', '1', '2', '3', '4', '5',
    			'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
    
    	public static String toHexString(byte[] b) { // String to byte
    		StringBuilder sb = new StringBuilder(b.length * 2);
    		for (int i = 0; i < b.length; i++) {
    			sb.append(HEX_DIGITS[(b[i] & 0xf0) >>> 4]);
    			sb.append(HEX_DIGITS[b[i] & 0x0f]);
    		}
    		return sb.toString();
    	}
    
    	public static String AndroidMd5(String s) {
    		try {
    			// Create MD5Util Hash
    			MessageDigest digest = MessageDigest
    					.getInstance("MD5");
    			digest.update(s.getBytes());
    			byte messageDigest[] = digest.digest();
    
    			return toHexString(messageDigest);
    		} catch (NoSuchAlgorithmException e) {
    			e.printStackTrace();
    		}
    
    		return "";
    	}
    
    	public static void main(String[] args) {
    
    		String m = MD5Util.str2MD5("swwwwwwwwwwdkinner");
    
    		System.out.print(m.length() + "    ");
    		System.out.println(m);
    
    	}
    }
    
    

    ###2.SHA

    SHA的全称是Secure Hash Algorithm,即安全散列算法。 1993年,安全散列算法(SHA)由美国国家标准和技术协会(NIST)提出,并作为联邦信息处理标准(FIPS PUB 180)公布, 1995年又发布了一个修订版FIPS PUB 180-1,通常称之为SHA-1。 SHA-1是基于MD4算法的,现在已成为公认的最安全的散列算法之一,并被广泛使用。SHA-1算法生成的摘要信息的长度为160位,由于生成的摘要信息更长,运算的过程更加复杂,在相同的硬件上, SHA-1的运行速度比MD5更慢,但是也更为安全。

    
    
    import com.google.common.base.Strings;
    
    import java.security.MessageDigest;
    
    /**
     * SHA的全称是Secure Hash Algorithm,即安全散列算法
     * Created by fangzhipeng on 2017/3/21.
     */
    public class SHAUtil {
    
        /**
         * 定义加密方式
         */
        private final static String KEY_SHA = "SHA";
        private final static String KEY_SHA1 = "SHA-1";
        /**
         * 全局数组
         */
        private final static String[] hexDigits = { "0", "1", "2", "3", "4", "5",
                "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
    
        /**
         * 构造函数
         */
        public SHAUtil() {
    
        }
    
        /**
         * SHA 加密
         * @param data 需要加密的字节数组
         * @return 加密之后的字节数组
         * @throws Exception
         */
        public static byte[] encryptSHA(byte[] data) throws Exception {
            // 创建具有指定算法名称的信息摘要
    //        MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
            MessageDigest sha = MessageDigest.getInstance(KEY_SHA1);
            // 使用指定的字节数组对摘要进行最后更新
            sha.update(data);
            // 完成摘要计算并返回
            return sha.digest();
        }
    
        /**
         * SHA 加密
         * @param data 需要加密的字符串
         * @return 加密之后的字符串
         * @throws Exception
         */
        public static String encryptSHA(String data) throws Exception {
            // 验证传入的字符串
            if (Strings.isNullOrEmpty(data)) {
                return "";
            }
            // 创建具有指定算法名称的信息摘要
            MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
            // 使用指定的字节数组对摘要进行最后更新
            sha.update(data.getBytes());
            // 完成摘要计算
            byte[] bytes = sha.digest();
            // 将得到的字节数组变成字符串返回
            return byteArrayToHexString(bytes);
        }
    
        /**
         * 将一个字节转化成十六进制形式的字符串
         * @param b 字节数组
         * @return 字符串
         */
        private static String byteToHexString(byte b) {
            int ret = b;
            //System.out.println("ret = " + ret);
            if (ret < 0) {
                ret += 256;
            }
            int m = ret / 16;
            int n = ret % 16;
            return hexDigits[m] + hexDigits[n];
        }
    
        /**
         * 转换字节数组为十六进制字符串
         * @param bytes 字节数组
         * @return 十六进制字符串
         */
        private static String byteArrayToHexString(byte[] bytes) {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < bytes.length; i++) {
                sb.append(byteToHexString(bytes[i]));
            }
            return sb.toString();
        }
    
        /**
         * 测试方法
         * @param args
         */
        public static void main(String[] args) throws Exception {
            String key = "123";
            System.out.println(encryptSHA(key));
        }
    }
    
    

    二、对称加密

    对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发送方将明文(原始数据)和加密密钥一起经过特殊加密算法处理后,生成复杂的加密密文进行发送,数据接收方收到密文后,若想读取原文,则需要使用加密使用的密钥及相同算法的逆算法对加密的密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发送和接收双方都使用这个密钥对数据进行加密和解密,这就要求加密和解密方事先都必须知道加密的密钥。

    1. DES算法

    1973 年,美国国家标准局(NBS)在认识到建立数据保护标准既明显又急迫的情况下,开始征集联邦数据加密标准的方案。 1975 年3月17日, NBS公布了IBM公司提供的密码算法,以标准建议的形式在全国范围内征求意见。经过两年多的公开讨论之后, 1977 年7月15日, NBS宣布接受这建议,作为联邦信息处理标准46 号数据加密标准(Data Encryptin Standard),即DES正式颁布,供商业界和非国防性政府部门使用。DES算法属于对称加密算法,明文按64位进行分组,密钥长64位,但事实上只有56位参与DES
    运算(第8、 16、 24、 32、 40、 48、 56、 64位是校验位,使得每个密钥都有奇数个1),分组后的明文和56位的密钥按位替代或交换的方法形成密文。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解,因此演变出了3DES算法。 3DES是DES向AES过渡的加密算法,它使用3条56位的密钥对数据进行三次加密,是DES的一个更安全的变形

    
    
    import java.io.IOException;
    import java.security.SecureRandom;
    
    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.DESKeySpec;
    
    
    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;
    
    /**
     * Data Encryptin Standard
     * 数据加密标准
     */
    public class DESUtil {
    
    
        private final static String DES = "DES";
    
        /**
         * Description 根据键值进行加密
         *
         * @param data
         * @param key  加密键byte数组
         * @return
         * @throws Exception
         */
        public static String encrypt(String data, String key) throws Exception {
            byte[] bt = encrypt(data.getBytes(), key.getBytes());
            String strs = new BASE64Encoder().encode(bt);
            return strs;
        }
    
        /**
         * Description 根据键值进行解密
         *
         * @param data
         * @param key  加密键byte数组
         * @return
         * @throws IOException
         * @throws Exception
         */
        public static String decrypt(String data, String key) throws Exception,
                Exception {
            if (data == null)
                return null;
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] buf = decoder.decodeBuffer(data);
            byte[] bt = decrypt(buf, key.getBytes());
            return new String(bt);
        }
    
        /**
         * Description 根据键值进行加密
         *
         * @param data
         * @param key  加密键byte数组
         * @return
         * @throws Exception
         */
        private static byte[] encrypt(byte[] data, byte[] key) throws Exception {
            // 生成一个可信任的随机数源
            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(DES);
    
            // 用密钥初始化Cipher对象
            cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
    
            return cipher.doFinal(data);
        }
    
    
        /**
         * Description 根据键值进行解密
         *
         * @param data
         * @param key  加密键byte数组
         * @return
         * @throws Exception
         */
        private static byte[] decrypt(byte[] data, byte[] key) throws Exception {
            // 生成一个可信任的随机数源
            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(DES);
    
            // 用密钥初始化Cipher对象
            cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
    
            return cipher.doFinal(data);
        }
    
        public static void main(String[]args)throws Exception{
           String  sStr=encrypt("122222112222:12343232323:jajwwwwslwskwkkwksk","wew2323w233321ws233w");
           System.out.println(sStr);
           String mStr=decrypt(sStr,"wew2323w233321ws233w");
           System.out.println(mStr);
        }
    }
    
    

    2. AES

    AES的全称是Advanced Encryption Standard,即高级加密标准,该算法由比利时密码学家Joan Daemen和Vincent Rijmen所设计,结合两位作者的名字,又称Rijndael加密算法,是美国联邦政府采用的一种对称加密标准,这个标准用来替代原先的DES算法,已经广为全世界所使用,已然成为对称加密算法中最流行的算法之一。AES算法作为新一代的数据加密标准汇聚了强安全性、高性能、高效率、易用和灵活等优
    点,设计有三个密钥长度:128,192,256位,比DES算法的加密强度更高,更为安全。

    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.util.Base64;
    import java.util.Scanner;
    
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.KeyGenerator;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    
    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;
    
    /**
     * Created by fangzhipeng on 2017/3/21.
     */
    public class AESUtil {
    
        static  byte[]  key = "w@#$4@#$s^&3*&^4".getBytes();
        final static String algorithm="AES";
    
        public static String encrypt(String data){
    
            byte[] dataToSend = data.getBytes();
            Cipher c = null;
            try {
                c = Cipher.getInstance(algorithm);
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            SecretKeySpec k =  new SecretKeySpec(key, algorithm);
            try {
                c.init(Cipher.ENCRYPT_MODE, k);
            } catch (InvalidKeyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            byte[] encryptedData = "".getBytes();
            try {
                encryptedData = c.doFinal(dataToSend);
            } catch (IllegalBlockSizeException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (BadPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            byte[] encryptedByteValue =     Base64.getEncoder().encode(encryptedData);
            return  new String(encryptedByteValue);//.toString();
        }
    
        public static String decrypt(String data){
    
            byte[] encryptedData  =  Base64.getDecoder().decode(data);
            Cipher c = null;
            try {
                c = Cipher.getInstance(algorithm);
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            SecretKeySpec k =
                    new SecretKeySpec(key, algorithm);
            try {
                c.init(Cipher.DECRYPT_MODE, k);
            } catch (InvalidKeyException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            byte[] decrypted = null;
            try {
                decrypted = c.doFinal(encryptedData);
            } catch (IllegalBlockSizeException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (BadPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return new String(decrypted);
        }
    
        public static void main(String[] args){
            String password=encrypt("12233440988:1239874389888:dd333");
            System.out.println(password);
            System.out.println(decrypt(password));
        }
    }
    
    
    

    ##三、非对称加密

    非对称加密算法又称为公开密钥加密算法,它需要两个密钥,一个称为公开密钥(public key),即公钥,另一个称为私有密钥(private key),即私钥。公钥与私钥需要配对使用,如果用公钥对数据进行加密,只有用对应的私钥才能进行解密,而如果使用私钥对数据进行加密,那么只有用对应的公钥才能进行解密。因为加密和解密使用的是两个不同的密钥,所以这种算法称为非对称加密算法。非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公钥向其它人公开,得到该公钥的乙方使用该密钥对机密信息进行加密后再发送给甲方,甲方再使用自己保存的另一把专用密钥,即私钥,对加密后的信息进行解密。

    RSA

    RSA非对称加密算法是1977年由Ron Rivest、 Adi Shamirh和LenAdleman开发的, RSA取名来自开发他们三者的名字。 RSA是目前最有影响力的非对称加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。 RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但反过来想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

    
    /**
     * Created by fangzhipeng on 2017/3/21.
     * RSA :RSA非对称加密算法是1977年由Ron Rivest、 Adi Shamirh和LenAdleman开发   *  的, RSA取名来
     *  自开发他们三者的名字。
     * 参考:http://blog.csdn.net/wangqiuyun/article/details/42143957
     */
    
    import java.io.*;
    import java.security.InvalidKeyException;
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.Base64;
    
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.NoSuchPaddingException;
    public class RSAUtil {
    
    
        /**
         * 字节数据转字符串专用集合
         */
        private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6',
                '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
    
        /**
         * 随机生成密钥对
         */
        public static void genKeyPair(String filePath) {
            // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
            KeyPairGenerator keyPairGen = null;
            try {
                keyPairGen = KeyPairGenerator.getInstance("RSA");
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            // 初始化密钥对生成器,密钥大小为96-1024位
            keyPairGen.initialize(1024,new SecureRandom());
            // 生成一个密钥对,保存在keyPair中
            KeyPair keyPair = keyPairGen.generateKeyPair();
            // 得到私钥
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            // 得到公钥
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            try {
                // 得到公钥字符串
                // 得到私钥字符串
                String privateKeyString =new String( Base64.getEncoder().encode(privateKey.getEncoded()));
                String publicKeyString =new String( Base64.getEncoder().encode(publicKey.getEncoded()));
                // 将密钥对写入到文件
    
                File file1=new File(filePath + "publicKey.keystore");
                File file2=new File(filePath + "privateKey.keystore");
                if(!file1.exists()) {
                    file1.createNewFile();
                }
                if(!file2.exists()) {
                    file2.createNewFile();
                }
                FileWriter pubfw = new FileWriter(filePath + "/publicKey.keystore");
                FileWriter prifw = new FileWriter(filePath + "/privateKey.keystore");
                BufferedWriter pubbw = new BufferedWriter(pubfw);
                BufferedWriter pribw = new BufferedWriter(prifw);
                pubbw.write(publicKeyString);
                pribw.write(privateKeyString);
                pubbw.flush();
                pubbw.close();
                pubfw.close();
                pribw.flush();
                pribw.close();
                prifw.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 从文件中输入流中加载公钥
         *
         * @param
         *
         * @throws Exception
         *             加载公钥时产生的异常
         */
        public static String loadPublicKeyByFile(String path) throws Exception {
            try {
                BufferedReader br = new BufferedReader(new FileReader(path
                        + "/publicKey.keystore"));
                String readLine = null;
                StringBuilder sb = new StringBuilder();
                while ((readLine = br.readLine()) != null) {
                    sb.append(readLine);
                }
                br.close();
                return sb.toString();
            } catch (IOException e) {
                throw new Exception("公钥数据流读取错误");
            } catch (NullPointerException e) {
                throw new Exception("公钥输入流为空");
            }
        }
    
        /**
         * 从字符串中加载公钥
         *
         * @param publicKeyStr
         *            公钥数据字符串
         * @throws Exception
         *             加载公钥时产生的异常
         */
        public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr)
                throws Exception {
            try {
                byte[] buffer = Base64.getDecoder().decode(publicKeyStr);
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
                return (RSAPublicKey) keyFactory.generatePublic(keySpec);
            } catch (NoSuchAlgorithmException e) {
                throw new Exception("无此算法");
            } catch (InvalidKeySpecException e) {
                throw new Exception("公钥非法");
            } catch (NullPointerException e) {
                throw new Exception("公钥数据为空");
            }
        }
    
        /**
         * 从文件中加载私钥
         *
         * @param
         *
         * @return 是否成功
         * @throws Exception
         */
        public static String loadPrivateKeyByFile(String path) throws Exception {
            try {
                BufferedReader br = new BufferedReader(new FileReader(path
                        + "/privateKey.keystore"));
                String readLine = null;
                StringBuilder sb = new StringBuilder();
                while ((readLine = br.readLine()) != null) {
                    sb.append(readLine);
                }
                br.close();
                return sb.toString();
            } catch (IOException e) {
                throw new Exception("私钥数据读取错误");
            } catch (NullPointerException e) {
                throw new Exception("私钥输入流为空");
            }
        }
    
        public static RSAPrivateKey loadPrivateKeyByStr(String privateKeyStr)
                throws Exception {
            try {
                byte[] buffer = Base64.getDecoder().decode(privateKeyStr);
                PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
            } catch (NoSuchAlgorithmException e) {
                throw new Exception("无此算法");
            } catch (InvalidKeySpecException e) {
                throw new Exception("私钥非法");
            } catch (NullPointerException e) {
                throw new Exception("私钥数据为空");
            }
        }
    
        /**
         * 公钥加密过程
         *
         * @param publicKey
         *            公钥
         * @param plainTextData
         *            明文数据
         * @return
         * @throws Exception
         *             加密过程中的异常信息
         */
        public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData)
                throws Exception {
            if (publicKey == null) {
                throw new Exception("加密公钥为空, 请设置");
            }
            Cipher cipher = null;
            try {
                // 使用默认RSA
                cipher = Cipher.getInstance("RSA");
                // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
                cipher.init(Cipher.ENCRYPT_MODE, publicKey);
                byte[] output = cipher.doFinal(plainTextData);
                return output;
            } catch (NoSuchAlgorithmException e) {
                throw new Exception("无此加密算法");
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
                return null;
            } catch (InvalidKeyException e) {
                throw new Exception("加密公钥非法,请检查");
            } catch (IllegalBlockSizeException e) {
                throw new Exception("明文长度非法");
            } catch (BadPaddingException e) {
                throw new Exception("明文数据已损坏");
            }
        }
    
        /**
         * 私钥加密过程
         *
         * @param privateKey
         *            私钥
         * @param plainTextData
         *            明文数据
         * @return
         * @throws Exception
         *             加密过程中的异常信息
         */
        public static byte[] encrypt(RSAPrivateKey privateKey, byte[] plainTextData)
                throws Exception {
            if (privateKey == null) {
                throw new Exception("加密私钥为空, 请设置");
            }
            Cipher cipher = null;
            try {
                // 使用默认RSA
                cipher = Cipher.getInstance("RSA");
                cipher.init(Cipher.ENCRYPT_MODE, privateKey);
                byte[] output = cipher.doFinal(plainTextData);
                return output;
            } catch (NoSuchAlgorithmException e) {
                throw new Exception("无此加密算法");
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
                return null;
            } catch (InvalidKeyException e) {
                throw new Exception("加密私钥非法,请检查");
            } catch (IllegalBlockSizeException e) {
                throw new Exception("明文长度非法");
            } catch (BadPaddingException e) {
                throw new Exception("明文数据已损坏");
            }
        }
    
        /**
         * 私钥解密过程
         *
         * @param privateKey
         *            私钥
         * @param cipherData
         *            密文数据
         * @return 明文
         * @throws Exception
         *             解密过程中的异常信息
         */
        public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData)
                throws Exception {
            if (privateKey == null) {
                throw new Exception("解密私钥为空, 请设置");
            }
            Cipher cipher = null;
            try {
                // 使用默认RSA
                cipher = Cipher.getInstance("RSA");
                // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
                cipher.init(Cipher.DECRYPT_MODE, privateKey);
                byte[] output = cipher.doFinal(cipherData);
                return output;
            } catch (NoSuchAlgorithmException e) {
                throw new Exception("无此解密算法");
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
                return null;
            } catch (InvalidKeyException e) {
                throw new Exception("解密私钥非法,请检查");
            } catch (IllegalBlockSizeException e) {
                throw new Exception("密文长度非法");
            } catch (BadPaddingException e) {
                throw new Exception("密文数据已损坏");
            }
        }
    
        /**
         * 公钥解密过程
         *
         * @param publicKey
         *            公钥
         * @param cipherData
         *            密文数据
         * @return 明文
         * @throws Exception
         *             解密过程中的异常信息
         */
        public static byte[] decrypt(RSAPublicKey publicKey, byte[] cipherData)
                throws Exception {
            if (publicKey == null) {
                throw new Exception("解密公钥为空, 请设置");
            }
            Cipher cipher = null;
            try {
                // 使用默认RSA
                cipher = Cipher.getInstance("RSA");
                // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
                cipher.init(Cipher.DECRYPT_MODE, publicKey);
                byte[] output = cipher.doFinal(cipherData);
                return output;
            } catch (NoSuchAlgorithmException e) {
                throw new Exception("无此解密算法");
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
                return null;
            } catch (InvalidKeyException e) {
                throw new Exception("解密公钥非法,请检查");
            } catch (IllegalBlockSizeException e) {
                throw new Exception("密文长度非法");
            } catch (BadPaddingException e) {
                throw new Exception("密文数据已损坏");
            }
        }
    
        /**
         * 字节数据转十六进制字符串
         *
         * @param data
         *            输入数据
         * @return 十六进制内容
         */
        public static String byteArrayToString(byte[] data) {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < data.length; i++) {
                // 取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
                stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);
                // 取出字节的低四位 作为索引得到相应的十六进制标识符
                stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
                if (i < data.length - 1) {
                    stringBuilder.append(' ');
                }
            }
            return stringBuilder.toString();
        }
    
    
    
        public static void main(String[] args) throws Exception {
            String filepath="F:/temp/";
            File file=new File(filepath);
            if(!file.exists()){
                file.mkdir();
            }
            genKeyPair(filepath);
            System.out.println("--------------公钥加密私钥解密过程-------------------");
            String plainText="1223333323:8783737321232:dewejj28i33e92hhsxxxx";
            //公钥加密过程
            byte[] cipherData=encrypt(loadPublicKeyByStr(loadPublicKeyByFile(filepath)),plainText.getBytes());
            String cipher=new String(Base64.getEncoder().encode(cipherData));
            //私钥解密过程
            byte[] res=decrypt(loadPrivateKeyByStr(loadPrivateKeyByFile(filepath)), Base64.getDecoder().decode(cipher));
            String restr=new String(res);
            System.out.println("原文:"+plainText);
            System.out.println("加密密文:"+cipher);
            System.out.println("解密:"+restr);
            System.out.println();
        }
    }
    
    

    注: 文字部分复制了《大型电商分布式系统实践 第一版 讲师 陈康贤》的第三课。代码来源于自己的整理,全部测试通过,应该没有坑。

    SouthEast
    扫码关注公众号有惊喜

    (转载本站文章请注明作者和出处 方志朋的博客

    展开全文
  • 网络安全:常见安全算法

    千次阅读 2019-07-22 11:10:50
    废话不多说,本文将介绍常见的几种安全算法:数字摘要,对称加密,非对称加密,数字签名,数字证书。 1.数字摘要 数字摘要(消息摘要)是将一个消息或者文本内容使用函数或算法转换成固定长度的值。 如 函数y= f...

    废话不多说,本文将介绍常见的几种安全算法:数字摘要,对称加密,非对称加密,数字签名,数字证书。

    1.数字摘要

    数字摘要(消息摘要)是将一个消息或者文本内容使用函数或算法转换成固定长度的值。

    如  函数y= f(x)   x即为消息或文本, y为数字摘要。当消息和摘要(y1)在网络传递时,如果消息在网络传递过程中被恶意的篡改了,接收者通过对消息使用相同的算法或函数重新计算得到新数字摘要(y2),新数字摘要(y2)与原数字摘要(y1)进行比较,就可以判断消息是否被篡改。因此数字摘要可以验证消息的完整性。

    hash碰撞:如果两个消息时相同的,计算出的值(数字摘要)一定时相同的,如果两个不同的消息,计算出的值不一定相同,这种情况称之为hash碰撞。因此一个hash函数的好坏取决于碰撞的概率,如果说攻击者能够利用hash碰撞轻易的伪造出不同的消息hash值(数字摘要)时相同的。那么这样的hash函数时危险的。可以认为,摘要的长度越长算法越安全。由于数字摘要并不包含原文的完整信息,因此,要从摘要信息逆向得出摘要的明文,原则上是不肯能完成的。

                                                    

    数字摘要的特点:

          (1)无论输入的消息有多长,计算出的摘要长度是固定的。MD5算法计算出的摘要长度是128位,SHA-1算法计算出的摘要160位。

          (2)一般输入的消息不同,则对应摘要不同,这种情况是hash碰撞。但消息相同,对应摘要必然相同。

          (3)摘要并不包含原文的完整信息,因此逆向得不到原文信息。如果你想通过穷举的方式,采用暴力手段,尝试每一个信息计算出摘要,然后于原摘要进行对比,是可以回复原文的,但以目前的计算水平来看,需要消耗很长时间,因此被认为是不可能实现的。

    接下来一起看一下获取数字摘要相关的算法。

    MD5 算法:     

     MD5(Message Digest  Algorithm 5) 信息摘要算法5,是数字摘要算法的一种实现摘要长度为128位。MD5由MD2,MD3,MD4改进而来,主要增强了算法复杂度和不可逆性。该算法具有普遍,稳定,快速的特点,因此业内广泛使用。目前主流编程语言都有MD5实现,下面是java中MD5的使用:

    public static byte[] encode(String content) throws Exception{
            //获取MD5算法
            MessageDigest  md = MessageDigest.getInstance("MD5");
         
           //通过MD5中digest方法获取数字摘要 
            byte[] bytes = md.digest(content.getBytes("utf-8"));
         
            return bytes;
    
    }
    
    //原文 content:hello,world
    //生成的摘要(16进制编码后):22bd33d4c72d1986ccb4227ff7fle7265
    

      SHA算法:    

       SHA(Secure Hash Algorithm) 安全散列算法 其修订版本 SHA-1 是基于MD4算法的,是目前公认的安全散列算法之一,其生成摘要的长度为160位。由于摘要 长度比MD5长,运算过程更加复杂,因此在相同的硬件上,SHA-1的效率相对MD5较慢,但安全性更高。下面是Java中SHA-1的使用:

    public static byte[] encode(String content) throws Exception{
           //获取SHA-1
           MessageDigest md = MessageDigest.getInstance("SHA-1");
    
           //获取摘要
           byte[] bytes = md.digest(content.getBytes("utf-8"));
    
           return bytes;
    
    }
    
    //原文 content: hello,world
    //数字摘要(16进制编码后):deb945d3e6fe72dbla290bcfcf53057clcaafdel

     16进制编码:

    16进制由0-9和a-f表示,其中a-f对应10进制中的10-15

    java 实现16进制编码:

       /**
         * byte数组 转换成 16进制小写字符串
         */
        public static String bytes2Hex(byte[] bytes) {
            if (bytes == null || bytes.length == 0) {
                return null;
            }
    
            StringBuilder hex = new StringBuilder();
    
            for (byte b : bytes) {
                hex.append(HEXES[(b >> 4) & 0x0F]);
                hex.append(HEXES[b & 0x0F]);
            }
    
            return hex.toString();
        }
    

    java 实现16进制解码:

       /**
         * 16进制字符串 转换为对应的 byte数组
         */
        public static byte[] hex2Bytes(String hex) {
            if (hex == null || hex.length() == 0) {
                return null;
            }
    
            char[] hexChars = hex.toCharArray();
            byte[] bytes = new byte[hexChars.length / 2];   // 如果 hex 中的字符不是偶数个, 则忽略最后一个
    
            for (int i = 0; i < bytes.length; i++) {
                bytes[i] = (byte) Integer.parseInt("" + hexChars[i * 2] + hexChars[i * 2 + 1], 16);
            }
    
            return bytes;
        }
    

    Base64编码:

    很多人认为Base64是安全加密算法,并且将其当作加密算法使用,实际并非如此,因为任何人得到Base编码后的内容,通过相同的方法就可以得到原文信息。因此Base64只能算作编码算法。下面是java中base64的使用:

    //编码
    private static String encode(byte[] bytes) throws Exception{
               BASE64Encoder encoder = new BASE64Encoder();
    
               return encoder.encode(bytes);
    }
    
    //解码
    private static byte[] decode(String content) throws Exception{
               BASE64Dncoder decoder = new BASE64Dncoder();
    
               return dncoder.decode(content);
    }

    2.对称加密:

    数据发送方将密文(明文通过密钥加密的)和加密密钥一起经过特殊加密算法处理后,生成复杂的加密密文进行发送,数据接收方是收到密文后,若想读取数据,则需要使用加密使用的密钥及相同算法的逆算法对加密的密文进行解密,才能使其回复可读明文,在对称加密算法中,使用的密钥只有一个,发送和接收方都使用这个密钥进行加密和解密,这就要求发送方和接受方事先必须知道加密的密钥。

            

    对称加密算法特点:算法公开,计算量小,加密速度快,加密效率高。其安全性依赖于密钥,因此保护密钥不被泄露至关重要。

    常见的对称加密:AES,DES等。

    AES:

    AES(Advanced Encryption Standard)高级加密标准,用来替代DES算法,是对称加密算法中最流行的算法之一。主要特点:强安全性,高性能,高效率,易用灵活等特点。设计有3个密钥长度(128,192,256位)比DES更安全。

    java中AES算法的使用:

    /**
     * 生成base64编码的密钥字符串
     */ 
    public static String genKeyAes() throws Exception{
      //获取AEA生成器
      KeyGenerator  keyGen = KeyGenerator.getInstance("AES");
     
     //设置密钥位数
      keyGen.init(128);
     
    //获取密钥
      SecretKey key = kenGen.generateKey();
     
      //将密钥转成base64字符串 
     String base64Str = byte2Base64(key.getEncode()); 
    
    return base64Str ;
    
    }
    
    
    
    /**
     * 将base64编码格式的密钥字符串 转成 SecretKey对象
     */ 
    public static SecretKey loadKeyAES(String base64Str) throws Exception{
      //获取密钥
      byte[] bytes = base642byte(base64Str);
     
      //将密钥转成 SecretKey对象
      SecretKey key = new SecretKeySpec(bytes,"AES");
    
       return key;
    
    }

    加密与解密:

    /**
     * 对称加密
     */
    public static String encryptAES(String source,SecretKey key) throws Exception{
         //实例化对象cipher
         Cipher cipher = Cipher.getInstance("AES");
       
         //初始化加密模式
         cipher.init(Cipher.ENCRYPT_MODE,key);
         
        //得到加密字节数组
         byte[] bytes = cipher.dofinal(source.getBytes());
        
        //将加密字节数组 转成base64编码格式字符串
        String miwen = byte2Base64(bytes);
       
      return miwen ;
    
    }
    
    
    /**
     * 对称解密
     */
    public static String decryptAES(String source,SecretKey key) throws Exception{
         //实例化对象cipher
         Cipher cipher = Cipher.getInstance("AES");
       
         //初始化加密模式
         cipher.init(Cipher.DECRYPT_MODE,key);
         
        //得到原文字节数组
         byte[] bytes = cipher.dofinal(source.getBytes());
        
        //将原文字节数组 转成base64编码格式字符串
        String yuanwen = byte2Base64(bytes);
       
      return yuanwen;
    
    }

                   

    DES基于java的用法和AES一样 只是将上诉代码中的"AES"换成 DES即可 这里就不多赘述了。

    3.非对称加密:

    非对称加密:需要两把密钥,一把公钥,一把私钥。公钥加密对应私钥解密,私钥加密对应公钥解密。

    非对称加密算法实现信息交换的基本过程:

                                 

    非对称加密的特点:非对称加密的公钥是公开的,因此不需要在网络上传送密钥,大大提高了安全性,但非对称加密比对称加密复杂,加密速度相对较慢。

    因此广泛使用非对称与对称加密结合使用的方法,优缺点互补,达到时间与安全的平衡。对称加密速度快,用来加密较长的文件(明文),然后用非对称加密来给文件密钥加密。

    当前使用最广泛的非对称加密算法为RSA。

    基于java的RSA算法的使用:

    公钥和私钥字符串:

    /**
     *获取keyPair对象
     */ 
    public static keyPair getKeyPair() throws Exception{
            //获取RSA生成器
            KeyPairGenerator  k = KeyPairGenerator.getInstance("RSA");
            
            //初始化密钥长度
            k.initialize(512);
           
            //获取keyPair对象
            KeyPair keyPair = k.generateKeyPair();
     
            return keyPair;
    
    }
    
    
    /**
     *获取公钥字符串:通过keyPair对象
     */ 
    
     public static String getPublicKey(KeyPair keyPair){
           //公钥对象
           PublicKey publicKey = keyPair.getPublic(); 
           
           //公钥字节数组
           byte[] bytes = publicKey.getEncode();
           
           //公钥转成base64格式编码字符串
           return byte2Base64(bytes);
    
    }
    
    
    /**
     *获取私钥字符串:通过keyPair对象
     */ 
    
     public static String getPrivateKey(KeyPair keyPair){
           //私钥对象
           PrivateKey privateKey = keyPair.getPublic(); 
           
           //私钥字节数组
           byte[] bytes = privateKey .getEncode();
           
           //私钥转成base64格式编码字符串
           return byte2Base64(bytes);
    
    }
    

    通过公钥和私钥字符串获取公钥对象(PublicKey)和私钥对象(PrivateKey):

    /**
     *获取PublicKey 对象
     */
    public static  PublicKey string2PublicKey(String pubStr) throws Exception{
         //将base64编码的字符串 转成 字节数组公钥
         byte[] keyBytes = base642byte(pubStr);
    
         //将字节数组公钥转成 X509EncodeKeySpec 对象
         X509EncodeKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
       
        //获取KeyFactory
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    
        //获取PublicKey 对象
        PublicKey publicKey = keyFactory .generateFactory(keySpec);
    
       return publicKey;
    
    }
    
    
    /**
     *获取PrivateKey 对象
     */
    public static  PrivateKey string2PrivateKey (String priStr) throws Exception{
         //将base64编码的字符串 转成 字节数组公钥
         byte[] keyBytes = base642byte(priStr);
    
         //将字节数组公钥转成 X509EncodeKeySpec 对象
         PKCS8EncodeKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
       
        //获取KeyFactory
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    
        //获取PrivateKey 对象
        PrivateKey privateKey = keyFactory .generateFactory(keySpec);
    
       return privateKey ;
    
    }

    根据PublicKey与PrivateKey 进行加密和解密,这里使用公钥加密,私钥解密:

    /**
     *公钥加密
     */
    public static String publicEncrypt(String content,PublicKey publicKey) throws Exception{
       //获取Cipher对象
       Cipher cipher = Cipher.getInstance("RSA");
       
       //初始化加密模式
       cipher.init(Cipher.ENCRYPT_MODE,publicKey);
    
       //获取公钥加密的密文字节数组
       byte[] bytes = cipher.dofinal(content.getBytes());
    
       //转成bas64编码格式的字符串
       return byte2Base64(bytes); 
    
    
    }
    
    
    /**
     *私钥解密
     */
    public static String privateDecrypt(String content,PrivateKey privateKey) throws Exception{
       //获取Cipher对象
       Cipher cipher = Cipher.getInstance("RSA");
       
       //初始化加密模式
       cipher.init(Cipher.DECRYPT_MODE,privateKey);
    
       //获取公钥加密的密文字节数组
       byte[] bytes = cipher.dofinal(content.getBytes());
    
       //转成bas64编码格式的字符串
       return byte2Base64(bytes); 
    
    
    }

    4.数字签名

    数字签名是对非对称加密与数字摘要的综合使用,指的是将通信内容的摘要信息使用发送者的私钥进行加密。

    接收方通过发送者的公钥解密得到摘要信息,然后使用发送者相同的摘要算法对原文进行摘要,将两者摘要信息进行对比校验,判断原文是否被串改。

                          

    校验是否被串改过程:

    介绍完上面的各种加密算法后,来个支付包加密流程,是各种加密算法的综合运用:

                                    

    流程讲解:

          主要看加密包(发送的数据包)部分:分为信息,签名,会话密钥。

         信息:将原文通过会话密钥(对称加密的密钥)加密生成密文           (步骤1)

         签名:将原文通过MD5进行数字摘要,在对摘要使用信息发送方A的私钥加密 生成签名    (步骤2)

         会话密钥:其实就是对称加密的密钥,可以是AES。使用接收方B的公钥加密会话密钥      (步骤3)

        将加密包发送给信息接收方B:                              

          使用接收方B的私钥解密 得到会话密钥     (步骤4)

          使用会话密钥对信息进行解密 得到原文     (步骤5)

          将原文使用相同的摘要算法MD5 得到摘要A     (步骤6)

          使用发送方A的公钥解密数字签名 得到 摘要B    步骤6)

          校验摘要A与摘要B是否相等,不相等,说明原文被篡改。

    本文主要参考书籍:

                                                                                   

    展开全文
  • 信息安全是近年来的热门话题,特别是最近随着物联网的全民化,安全已经成为移动支付,智能家居等领域...目前遇到的很多比特币钱包被盗,手机支付被盗刷等都与算法相关,读完本文,就可以让你成为安全算法领域的专家。

      信息安全是近年来的热门话题,特别是最近随着物联网的全民化,安全已经成为移动支付,智能家居等领域发展的核心议题,而安全的本质是算法和安全系统。读完本文,就可以让你成为安全算法领域的专家。

    一图文让你成为密码算法安全专家:国密算法与国际算法揭秘

    密码安全

    1.对称密码(现在最常用的基础密码算法)

    对称密码是一种用相同的密钥进行加密和解密的技术,用于确保消息的机密性。

    对称秘钥算法,加密芯片

    对称密码

    对称算法有几大类:

    DES算法(你的门禁用的就是这个算法哦)

    DES(Data Encryption Standard)是1977年美国联邦信息处理标准中所采用的一种对称码。

    DES是一种将64比特的明文加密成64比特的密文的对称密码算法,它的密钥长度是56比特。尽管从规格上来说,DES的密钥长度是64比特,但由于每隔7比特会设置一个用于错误检查的比特,因此实质上其实密钥长度是56比特。由于DES的密文可以在短时间内被破译,因此除了用它来解密以前的密文以外,现在我们不应该使用DES了。

    三重DES(3DES)

    三重DES是为了增加DES的强度,将DES重复3次所得到的一种密码算法,也称为TDEA,通常缩写为3DES。尽管三重DES目前还被银行等机构使用,但其处理速度不高,除了特别重视向下兼容性的情况以外,很少被用于新的用途。

    AES

    AES(Advanced Encryption Standard)是取代其前任标准(DES)而成为新标准的一种对称密码算法(Rijndael)。Rijndael是由比利时密码学家Joan Daemen和Vincent Rijmen设计的分组密码算法,于2000年被选为新一代的标准密码算法——AES。Rijndael的分组长度和密钥长度可以分别以32比特为单位在128比特到256比特的范围内进行选择。不过在AES的规格中,分组长度固定为128比特,密钥长度只有128、192、和256比特三种。

    2. 公钥密码(非对称密码算法,安全度更高的算法,银行卡取钱的时候会用到哦)

    公钥密码(非对称密码)中,密钥分为加密密钥和解密密钥两种。发送者用加密密钥对消息进行加密,接收者用解密密钥对密文进行解密。公钥算法主要用于身份认证领域。

    非对称算法,加密芯片和身份认证算法

    非对称算法

    RSA

    RSA是一种公钥密码算法,它的名字是由它的三位开发者,即Ron Rivest、Adi Shamir和Leonard Adleman的姓氏的首字母组成的(Rivest-Shamir-Adleman)。RSA的加密是求“E次方的 mod N”,而解密则是求“D次方的 mod N”

    密文 = 明文^E mod N明文 = 密文^D mod N

    椭圆曲线密码(ECC)

    椭圆曲线密码(Elliptic Curve Cryptography,ECC)是最近备受关注的一种公钥密码算法。它的特点是所需的密钥长度比RSA短。椭圆曲线密码是通过将椭圆曲线上的特定点进行特殊的乘法运算来实现的,它利用了这种乘法运算的逆运算非常困难这一特性。使用公钥密码能够解决密钥配送问题。公钥密码是密码学界的一项革命性发明,现代计算机和互联网所使用的密码技术都得益于公钥密码。

    尽管公钥密码能够解决对称密码中的密钥交换问题,但存在通过中间人攻击被伪装的风险,因此需要对带有数字签名的公钥进行认证。即使已经有了公钥密码,对称密码也不会消失。公钥密码的运行速度远远低于对称密码,因此在一般的通信过程中,往往会配合使用这两种密码,即用对称密码提高处理速度,用公钥密码解决密钥配送问题。这样的方式称为混合密码系统。

    3.单向散列函数(HASH)

    单向散列函数有一个输入和一个输出,其中输入称为消息(message),输出称为散列值(hash code)。单向散列函数可以根据消息的内容计算出散列值,而散列值就可以被用来检查消息的完整性。散列值的长度和消息的长度无关。无论消息是1比特,还是100MB,甚至是100GB,单向散列函数都会计算出固定长度的散列值。以SHA-256单向散列函数为例,它所计算出的散列值的长度永远是256比特(32字节)。为了能够确认完整性,消息中哪怕只有1比特的改变,也会产生不同的散列值。

    单向散列函数输出的散列值也称为消息摘要(message digest)或者指纹(fingerprint)

    HASH 算法,比特币硬件钱包

    HASH

    如果想进一步了解移动设备安全方案资料,可加微信 “seciot”并交流。

    MD4、MD5(记不记得电影和文件下载的MD5校验?)

    MD(Messge Digest)4是由Rivest于1990年设计的单向散列函数,能够产生128比特的散列值。现在它已经不安全了。MD(Messge Digest)5是由Rivest于1991年设计的单向散列函数,能够产生128比特的散列值。MD5的强抗碰撞性已经被攻破。也就是说,现在已经能够产生具备相同散列值的两条不同的消息,因此它也不安全了。

    SHA-1、SHA-256、SHA-384、SHA512

    SHA-1是由NIST(美国国家标准技术研究所)设计的一种能够产生160比特的散列值的单向散列函数。现在已不推荐使用。SHA-256、SHA-384、SHA512都是由NIST设计的单向散列函数,它们的散列值长度分别为256比特、384比特、和512比特。这些单向散列函数合起来统称SHA-2。

    SHA-1的强抗碰撞性已于2005年被攻破,不过,SHA-2还尚未被攻破。

    单向散列函数能够辨别出“篡改”,但无法辨别出“伪装”,这时就需要进行认证。

    4. 消息认证码

    消息认证码(Message Authentication Code)是一种确认完整性并进行认证的技术,简称为MAC。

    消息认证指的是“消息来自正确的发送者”这一性质。消息认证码的输入包括任意长度的消息和一个发送者与接受者之间共享的密钥,它可以输出固定长度的数据,这个数据成为MAC值。

    要计算MAC必须持有共享密钥,没有共享密钥的人就无法计算MAC值,消息认证码正是利用这一性质来完成认证的。此外,和单向散列函数的散列值一样,哪怕消息中发生1比特的变化,MAC值也会产生变化,消息认证码正是利用这一性质来确认完整性的。消息认证码可以说是一种与密钥相关联的单向散列函数。

    消息认证码可以使用单向散列函数和对称密码等技术来实现。

    MAC和HASH对比,加密芯片

    MAC与HASH比较

    MAC流程,加密芯片

    MAC流程

    HMAC

    HMAC是一种使用单向散列函数来构造消息认证码的方法,其中HMAC的H就是Hash的意思。

    消息认证码也不能解决所有的问题,例如“对第三方证明”,和“防止否认”,这两个问题就无法通过消息认证码来解决。

    5. 数字签名

    消息认证码之所以无法防止否认,是因为消息认证码需要在发送者和接收者两者之间共享一个密钥。

    数字签名是一种能够对第三方进行消息认证,并能够防止通信对象作出否认的认证技术。

    数字签名中也同样会使用公钥和私钥组成的密钥对,不过这两个密钥的用法和公钥密码是相反的,即用私钥加密相当于生成签名,而用公钥解密则相当于验证签名。

    PKI签名与验签 加密芯片

    生成签名和验证签名

    实现数字签名使用的算法如下:

    RSA

    RSA是一种公钥密码算法,它的名字是由它的三位开发者,即Ron Rivest、Adi Shamir和Leonard Adleman的姓氏的首字母组成的(Rivest-Shamir-Adleman)。

    用RSA生成签名和验证签名的过程可用下列公式来表述:

    签名 = 消息^D mod N由签名得到的消息 = 密文^E mod N

    EIGamal

    EIGamal方式是由Taher EIGamal设计的公钥算法。利用了mod N 下求离散对数的困难度。EIGamal方式可以被用于公钥密码和数字签名。

    DSA

    DSA(Digital Signature Algorithm)是一种数字签名算法,是由NIST于1991年制定的数字签名规范。

    DSA是Scnorr算法与EIGammal方式的变体,只能被用于数字签名。

    ECDSA

    ECDSA(Elliptic Curve Digital Signature Algorithm)是一种利用椭圆曲线密码来实现的数字签名算法。

    Rabin方式

    Rabin方式是由M.O.Rabin设计的公钥算法。利用了在mod N下求平方根的困难度。Rabin方式可以被用于公钥密码和数字签名。

    用数字签名既可以识别出篡改和伪装,还可以防止否认,但是无法确认用于验证签名的公钥属于真正的发送者的。

    要确认公钥是否合法,可以对公钥施加数字签名,这就是证书。

    6.证书

    公钥证书(Public-Key Certificate,PKC)其实和驾照很相似,里面记有姓名、组织、邮箱、地址等个人信息,以及属于此人的公钥,并由认证机构(Certification Authority,CA)施加数字签名。只要看到公钥证书,我们就可以知道认证机构认定该公钥的确属于此人。公钥证书也简称为证书。

    认证机构就是能够认定“公钥确实属于此人”并能够生成数字签名的个人或者组织。

    PKI认证

    消息发送者利用认证机构向消息接收者发送密文

    X.509

    X.509是一种证书生成和交换的标准规范。

    7.PKI(身份认证,银行U盾就是这个体系啦)

    PKI(Public-Key Infrastructure)是为了能够更有效地运用公钥而制定的一系列规范和规格的总称。X.509也是PKI的一种。

    密钥

    各种不同的密钥

    1.对称密码的密钥与公钥密码的密钥

    2.消息认证码的密钥与数字签名的密钥

    3.用于确保机密性的密钥与用于认证的密钥

    4.会话密钥与主密钥

    当我们访问以 https:// 开头的网页时,Web服务器和浏览器之间会进行基于SSL/TLS的加密通信。在这样的通信中所使用的密钥是仅限于本次通信的一次性密钥,下次通信时就不能使用了。像这样每次通信只能使用一次的密钥称为会话密钥(session key)。

    相对于每次通信都更换的会话密钥,一直被重复使用的密钥称为主密钥(master key)。

    5.用于加密内容的密钥与用于加密密钥的密钥

    一般来说,加密的对象是用户直接使用的消息(内容),这样的情况下所使用的密钥称为CEK(Contents Encrypting Key);相对地,用于加密密钥的密钥则称为KEK(Key Encrypting Key)。

    上面提到的会话密钥都是被作为CEK使用的,而主密钥则是被作为KEK使用的。

    一图文让你成为密码算法安全专家:国密算法与国际算法揭秘

    CEK与KEK

    CEK与KEK.png

    Diffe-Hellman密钥交换

    Diffe-Hellman密钥交换是1976年由Whitfield Diffe和Martin Hellman共同发明的一种算法。使用这种算法,通信双方通过交换一些可以公开的信息就能够生成出共享的秘密数字,而这一秘密数字就可以被用作对称密码的密钥。

    一图文让你成为密码算法安全专家:国密算法与国际算法揭秘

    Diffee-Hellman密钥交换

    8. 随机数(比特币钱包的最爱)

    随机数的用处

    • 生成密钥:用于对称密码和消息认证码。

    • 生成密钥对:用于公钥密码和数字签名。

    • 生成初始化向量(IV):用于分组密码的CBC、CFB和OFB模式。

    • 生成nonce:用于防御重放攻击以及分组密码的CTR模式等。

    • 生成OTP:用于基于口令的密码等。

    (笔者去年做的一个项目比特币硬件钱包,核心就是考验硬件安全和随机数安全,目前遇到的很多比特币钱包被盗,手机支付被盗刷等都与算法相关。)

    随机数的性质

    • 随机性(弱伪随机数)

    • 不可预测性(强伪随机数)

    • 不可重现性(真随机数)

    真随机数生成器

    通过硬件生成的随机数列,是根据传感器收集的热量、声音的变化等事实上无法预测和重现的自然现象信息来生成的。像这样的硬件设备就称为随机数生成器。

    伪随机数生成器

    而可以生成随机数的软件则称为伪随机数生成器。因为仅靠软件无法生成真随机数,因此要加上一个“伪”字。

    9. 国密算法:中国自主的密码算法标准(国家金融安全的核心,要强烈支持)

    保证安全最根本的方法是基础软件和基础硬件都是自己控制,目前我国无法短期国产化的情况下,数据加密是最好的方式。如果加密算法以及实现都是外国提供的,安全性从何说起,所以我国国家密码局发布了自主可控的国密算法,包含SM1\ SM2\ SM3\ SM4算法

    SM1算法

    分组密码算法是分组对称加解密算法,分组长度为128位,密钥长度都为128 比特,算法安全保密强度及相关软硬件实现性能与AES 相当,算法不公开,仅以IP 核的形式存在于芯片中。采用该算法已经研制了系列芯片、智能IC 卡、智能密码钥匙、加密卡、加密机等安全产品,广泛应用于电子政务、电子商务及国民经济的各个应用领域(包括国家政务通、警务通等重要领域)。

    SM4分组密码算法

    是用于无线局域网和可信计算系统的专用分组密码算法,该算法的分组长度为128比特,密钥长度为128比特。SM4算法是我国制定WAPI标准的组成部分,同时也可以用于其它环境下的数据加密保护。

    SM1算法和SM4算法是我国自主设计的分组对称密码算法,用于实现数据的加密/解密运算,以保证数据和信息的机密性。SM1算法和SM4算法均可以用于网络数据的加密保护,以及存储数据或文件的加密保护。

    SM1算法和SM4算法还能够抵抗针对分组密码算法的各种攻击方法,包括穷举搜索攻击、差分攻击、线性攻击等,在实际应用中能够抵抗这些攻击手段。国际上常见的分组密码算法,包括国际上的DES算法、AES算法、IDEA算法等。

    SM2算法

    由国家密码管理局于2010年12月17日发布,全称为椭圆曲线算法。椭圆曲线并不是椭圆,之所以称为椭圆曲线是因为它们是用三次方程来表示的,并且该方程与计算椭圆周长的方程相似。

    摘要算法——国产SM3

    摘要函数在密码学中具有重要的地位,被广泛应用在数字签名,消息认证,数据完整性检测等领域。摘要函数通常被认为需要满足三个基本特性:碰撞稳固性,原根稳固性和第二原根稳固性。SM3密码摘要算法是中国国家密码管理局2010年公布的中国商用密码杂凑算法标准。SM3算法适用于商用密码应用中的数字签名和验证,是在SHA-256基础上改进实现的一种算法。SM3算法采用Merkle-Damgard结构,消息分组长度为512位,摘要值长度为256位。

    SM3算法的压缩函数与SHA-256的压缩函数具有相似的结构,但是SM3算法的设计更加复杂,比如压缩函数的每一轮都使用2个消息字。

    现今为止,SM3算法的安全性相对较高。

    当然,算法本身安全了,并不表示就安全了。 在很多流程中,都有可能出现漏洞。举个例子,保险箱虽然很牛逼,但是,保险箱的钥匙如果被偷走,那保险箱就没什么安全性了。

    因此,无论算法的数学理论有多牛逼,如果运行算法的过程不是安全的,就容易泄露秘钥。

    对算法的攻击,一种常见的手段是SCA(side channel attack)。可以很容易的攻击得到算法的密钥。RSA/AES/DES都可以被攻破。作为follow国际算法的国密算法SM2、SM4,也是一样的道理。

    所以,金融领域的产品,都要求必须经过算法的安全认证,在这里,带独立算法引擎的安全硬件就非常重要了。认证过程就是要多算法实现的安全性进行认证。具体的,就是做各种各样的攻击,看是否能得到密钥。同样的,国密局要求,内置了国密算法的安全产品,要想过国密的认证,就必须要做到算法实现的安全性。

    如果想进一步了解移动设备安全和算法安全资料,可加微信seciot交流。

    展开全文
  • 常见的安全算法--单向加密--Hash算法

    千次阅读 2019-07-25 11:31:17
    常见安全算法—数字摘要 数字摘要也称为消息摘要,它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向 Hash函数对消息进行计算而产生。如果消息在传递的途中改变了,接收者通过对收到消息采用相同的Hash...
  • 安全算法梳理

    千次阅读 2016-09-05 01:12:15
      经常见到RSA、MD5、SHA系列算法,另外还有数字摘要、数字签名、数字证书等名词,以及对称加密与非对称加密。他们之间到底是什么关系呢?下面就通过这篇文章来梳理一下。 一、加密算法  加密算法,简而言之...
  • 国产密码安全算法总结

    万次阅读 多人点赞 2017-03-09 17:41:21
    算法是由国家密码管理局编制的一种商用密码分组标准对称算法,分组长度和密钥长度均为128位,算法安全保密强度及相关软硬件实现性能与AES算法相当,目前该算法尚未公开,仅以IP核的形式存在于芯片中。2、SM2算法...
  • 安全算法—SHA-256算法

    千次阅读 2018-07-15 14:39:47
    1. 什么是SHA-256?SHA-256是SHA2中的一种。对于长度L(L&...2. SHA-256算法实现步骤2.1 把消息转换为位字符串 SHA-256算法是按照位作为输入,所以进行计算前必须把原始消息(比如字符串、文件等)...
  • 四种最常见的安全算法总结

    千次阅读 2017-04-07 11:16:21
    最近项目用到一些加密和安全算法,浏览了一些资料,  总觉得缺少一篇让新手快速入门的基础而且比较全面的文章,  这里把一些常用的安全算法和自己的总结发出来,有不对的地方请大家多多指教,    Orz~-~
  • 密码学安全算法--对称加密算法

    千次阅读 2017-06-04 21:45:50
    最常见对称加密算法是:DES、3DES、AES、RC4。 对称加密算法基本原理 先上图,对称加密工作过程 在整个工作过程中涉及到以下几个概念 - 明文:也就是原始信息或者说原始数据。也就是上图中的A。 - 加密算法...
  • 什么是DES安全算法

    千次阅读 2016-04-20 13:58:32
    http://baike.baidu.com/link?url=a8RxsKgXSz3MIQNqzEjvxsIiTD7w5k171bi-KdPKH31aEu-9YWZ8PVBegLeO1oNYBbzw-tYKicuVl3quFTfXAqDES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,...
  • 安全算法—Hash算法总结(一)

    千次阅读 2018-07-10 16:37:34
    Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远...
  • 信息安全算法整理

    千次阅读 2018-01-13 11:56:37
    密钥编排算法:分为C0 D0 28 + 28 然后循环左移,1 2 9 16 移动一位其余移动两位 懒得写了,crtl + c AES加密: 密钥加 轮函数10轮: 字节代换s盒: 行移位:0 1 2 3 列混合:和c(x)做多项式乘法 ...
  • 通常情况下,在CANoe的Diagnostics/ISOTPConfiguration对话框中加载诊断描述文件(cdd、pdx、mdx等)后,我们就可以在诊断控制台(Diagnostic Console)面板里进行诊断服务的相关操作,但是在处理安全访问时就不能...
  • 当安全遇上AI 阿里聚安全算法挑战赛 队伍经验分享

    千次阅读 多人点赞 2020-04-05 20:55:27
      本届线上选拔赛赛题包括了《人机行为识别》、《SQL注入检测》和《社区反垃圾》,首次把风控、网络安全及内容安全的多维度数据结合的算法比赛。赛题紧贴业务,将实际存在的一些难题和数据呈现出来。《人机行为...
  • CANoe诊断功能——安全算法调用介绍

    千次阅读 2020-08-14 14:28:23
    通常情况下,在CANoe中加载诊断数据库cdd文件后,我们就可以在DiagnosticConsole诊断面板里进行安全访问相关操作。但是至少要需要手动依次触发3个诊断命令(如下图):扩展模式切换(10 03)- 请求种子(27 03)-...
  • 安全算法(一)数字摘要

    千次阅读 2016-06-20 17:04:03
    它是一种单向的,不可逆的加密算法。发送方:采用单向hash函数对消息进行计算,得到摘要。发送消息和摘要。接收方:把接收的消息,按着同样的hash函数计算,新产生的摘要和发送来的原摘要进行对比。如果2个摘要不...
  • 安全算法:3DES密钥长度

    万次阅读 2012-10-18 13:57:08
    DES的密钥长度为8字节,3DES的密钥长度为3*8=24字节。 Cipher=Ek3(Dk2(Ek1(Plain)));--使用K1加密,再使用K2对K1加密的结果解密,最后使用K3对K2解密的结果再加密,第三次的结果作为最终的密文。...
  • 1. 基于对称密钥的加密算法主要有DES、RC4、RC5, AES  对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法。有时又叫传统密码算法,就是加密...它要求发送方和接收方在安全通信之前,商定一个密钥。对称算法
  • 无锁的 ( lock-free ) 线程安全算法

    万次阅读 2007-08-08 14:36:00
    友情提示:对 Lock-free 算法没概念的朋友,请先看下面的参考。算法描述Lock-free 算法的基础是 CAS (Compareand-Swap) 原子操作。当某个地址的原始值等于某个比较值时,把值改成新值,无论有否修改,返回这个地址的...
  • 密码算法安全性列表

    千次阅读 2015-03-28 10:14:10
    业界已知不安全算法  对称算法:DES在所有场景下都不安全。  对称算法:3DES在密钥长度256以下,k1=k2=k3时不安全。  对称算法:SKIPJACK和RC2在所有场景下都不安全。  对称算法:RC4和BlowFish当密钥长度...
  • 常见的几种安全加密算法

    千次阅读 2017-11-17 10:58:12
    本文整理了常见的安全算法,包括MD5、SHA、DES、AES、RSA等,并写了完整的工具类(Java 版),工具类包含测试,大家可以放心使用。一、数字摘要算法 数字摘要也称为消息摘要,它是一个唯一对应一个消息或文本的固定...
  • 银行家算法安全算法

    万次阅读 2016-10-09 01:15:40
    安全序列是指存在一个进程序列{P1,…,Pn}是安全的,不会死锁(至少两个线程占有某资源A,但是都不满足,剩余的资源A分配给谁仍然无法满足),安全状态如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统...
  • 银行家算法安全算法笔记

    万次阅读 多人点赞 2018-07-01 15:57:55
    银行家算法简框图 “`flow st=&amp;amp;gt;start: 开始 e=&amp;amp;gt;end: 结束 cond1=&amp;amp;gt;condition: 资源请求合法性检查 op1=&amp;amp;gt;operation: 进行尝试性的资源分配 op2=&...
  • Python3实现银行家算法安全算法

    千次阅读 2017-11-20 22:17:35
    Python3实现银行家算法安全算法学习期间写的,希望大家一起进步。 Available = [] #各可用资源数目 Used ={} #某进程目前占有各资源数 Need = {} #某进程目前需求资源数 zhan = [] #临时存储列表 order = [] #...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 632,736
精华内容 253,094
关键字:

安全算法