精华内容
下载资源
问答
  • 对称加密与非对称加密理解和非对称加密的java例子 1.对称加密:一般小于256 bit的密钥,密钥越大越安全,但是解密和加密时间越长。加密和解密都是用的相同的密钥,快速简单 2.非对称加密:有公钥和私钥,只有私钥...
    对称加密与非对称加密理解和非对称加密的java例子
    1.对称加密:一般小于256 bit的密钥,密钥越大越安全,但是解密和加密时间越长。加密和解密都是用的相同的密钥,快速简单
    2.非对称加密:有公钥和私钥,只有私钥才能打开公钥,比如:你向银行请求公钥,银行将公钥发给你,你使用公钥对消息加密,那么只有私钥的持有人--银行才能对你的消息解密。与对称加密不同的是,银行不需要将私钥通过网络发送出去,因此安全性大大提高。但是速度慢
    (1) Alice需要在银行的网站做一笔交易,她的浏览器首先生成了一个随机数作为对称密钥。
    (2) Alice的浏览器向银行的网站请求公钥。
    (3) 银行将公钥发送给Alice。
    (4) Alice的浏览器使用银行的公钥将自己的对称密钥加密。
    (5) Alice的浏览器将加密后的对称密钥发送给银行。
    (6) 银行使用私钥解密得到Alice浏览器的对称密钥。
    (7) Alice与银行可以使用对称密钥来对沟通的内容进行加密与解密了。
    3.rsa公钥加密私钥解密算法实例
    公钥加密不能超过117   私钥解密不能超过128     不过在此代码中已经分段处理了
    3.1新建java工程,导入jar包

    package com.zl.test3;
    
    import java.io.BufferedReader;  
    import java.io.BufferedWriter;  
    import java.io.ByteArrayOutputStream;
    import java.io.FileReader;  
    import java.io.FileWriter;  
    import java.io.IOException;  
    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 javax.crypto.BadPaddingException;  
    import javax.crypto.Cipher;  
    import javax.crypto.IllegalBlockSizeException;  
    import javax.crypto.NoSuchPaddingException;  
      
      
    public class RSAEncrypt {  
        /** 
         * 字节数据转字符串专用集合 
         */  
        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 publicKeyString = Base64.encode(publicKey.getEncoded());  
                // 得到私钥字符串  
                String privateKeyString = Base64.encode(privateKey.getEncoded());  
                // 将密钥对写入到文件  
                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 in 
         *            公钥输入流 
         * @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.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 keyFileName 
         *            私钥文件名 
         * @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.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[] data)  
                throws Exception {  
            if (publicKey == null) {  
                throw new Exception("加密公钥为空, 请设置");  
            }  
            Cipher cipher = null;  
            try {  
                // 使用默认RSA  
                cipher = Cipher.getInstance("RSA");  
                cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
                int inputLen = data.length;
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                int offSet = 0;
                byte[] cache;
                int i = 0;
                // 对数据分段加密
                while (inputLen - offSet > 0) {
                    if (inputLen - offSet > 117) {
                        cache = cipher.doFinal(data, offSet, 117);
                    } else {
                        cache = cipher.doFinal(data, offSet, inputLen - offSet);
                    }
                    out.write(cache, 0, cache.length);
                    i++;
                    offSet = i * 117;
                }
                byte[] encryptedData = out.toByteArray();
                out.close();
                return encryptedData;
    //            byte[] output = cipher.doFinal(data);  
    //            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);  
             // 加密时超过117字节就报错。为此采用分段加密的办法来加密  
                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[] encryptedData)  
                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);  
                int inputLen = encryptedData.length;
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                int offSet = 0;
                byte[] cache;
                int i = 0;
                // 对数据分段解密
                while (inputLen - offSet > 0) {
                    if (inputLen - offSet > 128) {
                        cache = cipher.doFinal(encryptedData, offSet, 128);
                    } else {
                        cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                    }
                    out.write(cache, 0, cache.length);
                    i++;
                    offSet = i * 128;
                }
                byte[] decryptedData = out.toByteArray();
                out.close();
                return decryptedData;
    //            byte[] output = cipher.doFinal(encryptedData);  
    //            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();  
        }  
    }  
    3.2
    package com.zl.test3;
    /**
     * 
     * @author zenglong
     *
     * @Description: Base64算法
     *
     */
    public final class Base64 {  
    	  
        static private final int     BASELENGTH           = 128;  
        static private final int     LOOKUPLENGTH         = 64;  
        static private final int     TWENTYFOURBITGROUP   = 24;  
        static private final int     EIGHTBIT             = 8;  
        static private final int     SIXTEENBIT           = 16;  
        static private final int     FOURBYTE             = 4;  
        static private final int     SIGN                 = -128;  
        static private final char    PAD                  = '=';  
        static private final boolean fDebug               = false;  
        static final private byte[]  base64Alphabet       = new byte[BASELENGTH];  
        static final private char[]  lookUpBase64Alphabet = new char[LOOKUPLENGTH];  
      
        static {  
            for (int i = 0; i < BASELENGTH; ++i) {  
                base64Alphabet[i] = -1;  
            }  
            for (int i = 'Z'; i >= 'A'; i--) {  
                base64Alphabet[i] = (byte) (i - 'A');  
            }  
            for (int i = 'z'; i >= 'a'; i--) {  
                base64Alphabet[i] = (byte) (i - 'a' + 26);  
            }  
      
            for (int i = '9'; i >= '0'; i--) {  
                base64Alphabet[i] = (byte) (i - '0' + 52);  
            }  
      
            base64Alphabet['+'] = 62;  
            base64Alphabet['/'] = 63;  
      
            for (int i = 0; i <= 25; i++) {  
                lookUpBase64Alphabet[i] = (char) ('A' + i);  
            }  
      
            for (int i = 26, j = 0; i <= 51; i++, j++) {  
                lookUpBase64Alphabet[i] = (char) ('a' + j);  
            }  
      
            for (int i = 52, j = 0; i <= 61; i++, j++) {  
                lookUpBase64Alphabet[i] = (char) ('0' + j);  
            }  
            lookUpBase64Alphabet[62] = (char) '+';  
            lookUpBase64Alphabet[63] = (char) '/';  
      
        }  
      
        private static boolean isWhiteSpace(char octect) {  
            return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);  
        }  
      
        private static boolean isPad(char octect) {  
            return (octect == PAD);  
        }  
      
        private static boolean isData(char octect) {  
            return (octect < BASELENGTH && base64Alphabet[octect] != -1);  
        }  
      
        /** 
         * Encodes hex octects into Base64 
         * 
         * @param binaryData Array containing binaryData 
         * @return Encoded Base64 array 
         */  
        public static String encode(byte[] binaryData) {  
      
            if (binaryData == null) {  
                return null;  
            }  
      
            int lengthDataBits = binaryData.length * EIGHTBIT;  
            if (lengthDataBits == 0) {  
                return "";  
            }  
      
            int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;  
            int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;  
            int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;  
            char encodedData[] = null;  
      
            encodedData = new char[numberQuartet * 4];  
      
            byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;  
      
            int encodedIndex = 0;  
            int dataIndex = 0;  
            if (fDebug) {  
                System.out.println("number of triplets = " + numberTriplets);  
            }  
      
            for (int i = 0; i < numberTriplets; i++) {  
                b1 = binaryData[dataIndex++];  
                b2 = binaryData[dataIndex++];  
                b3 = binaryData[dataIndex++];  
      
                if (fDebug) {  
                    System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);  
                }  
      
                l = (byte) (b2 & 0x0f);  
                k = (byte) (b1 & 0x03);  
      
                byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);  
                byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);  
                byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);  
      
                if (fDebug) {  
                    System.out.println("val2 = " + val2);  
                    System.out.println("k4   = " + (k << 4));  
                    System.out.println("vak  = " + (val2 | (k << 4)));  
                }  
      
                encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];  
                encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];  
                encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];  
                encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];  
            }  
      
            // form integral number of 6-bit groups  
            if (fewerThan24bits == EIGHTBIT) {  
                b1 = binaryData[dataIndex];  
                k = (byte) (b1 & 0x03);  
                if (fDebug) {  
                    System.out.println("b1=" + b1);  
                    System.out.println("b1<<2 = " + (b1 >> 2));  
                }  
                byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);  
                encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];  
                encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];  
                encodedData[encodedIndex++] = PAD;  
                encodedData[encodedIndex++] = PAD;  
            } else if (fewerThan24bits == SIXTEENBIT) {  
                b1 = binaryData[dataIndex];  
                b2 = binaryData[dataIndex + 1];  
                l = (byte) (b2 & 0x0f);  
                k = (byte) (b1 & 0x03);  
      
                byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);  
                byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);  
      
                encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];  
                encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];  
                encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];  
                encodedData[encodedIndex++] = PAD;  
            }  
      
            return new String(encodedData);  
        }  
      
        /** 
         * Decodes Base64 data into octects 
         * 
         * @param encoded string containing Base64 data 
         * @return Array containind decoded data. 
         */  
        public static byte[] decode(String encoded) {  
      
            if (encoded == null) {  
                return null;  
            }  
      
            char[] base64Data = encoded.toCharArray();  
            // remove white spaces  
            int len = removeWhiteSpace(base64Data);  
      
            if (len % FOURBYTE != 0) {  
                return null;//should be divisible by four  
            }  
      
            int numberQuadruple = (len / FOURBYTE);  
      
            if (numberQuadruple == 0) {  
                return new byte[0];  
            }  
      
            byte decodedData[] = null;  
            byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;  
            char d1 = 0, d2 = 0, d3 = 0, d4 = 0;  
      
            int i = 0;  
            int encodedIndex = 0;  
            int dataIndex = 0;  
            decodedData = new byte[(numberQuadruple) * 3];  
      
            for (; i < numberQuadruple - 1; i++) {  
      
                if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))  
                    || !isData((d3 = base64Data[dataIndex++]))  
                    || !isData((d4 = base64Data[dataIndex++]))) {  
                    return null;  
                }//if found "no data" just return null  
      
                b1 = base64Alphabet[d1];  
                b2 = base64Alphabet[d2];  
                b3 = base64Alphabet[d3];  
                b4 = base64Alphabet[d4];  
      
                decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);  
                decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));  
                decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);  
            }  
      
            if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {  
                return null;//if found "no data" just return null  
            }  
      
            b1 = base64Alphabet[d1];  
            b2 = base64Alphabet[d2];  
      
            d3 = base64Data[dataIndex++];  
            d4 = base64Data[dataIndex++];  
            if (!isData((d3)) || !isData((d4))) {//Check if they are PAD characters  
                if (isPad(d3) && isPad(d4)) {  
                    if ((b2 & 0xf) != 0)//last 4 bits should be zero  
                    {  
                        return null;  
                    }  
                    byte[] tmp = new byte[i * 3 + 1];  
                    System.arraycopy(decodedData, 0, tmp, 0, i * 3);  
                    tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);  
                    return tmp;  
                } else if (!isPad(d3) && isPad(d4)) {  
                    b3 = base64Alphabet[d3];  
                    if ((b3 & 0x3) != 0)//last 2 bits should be zero  
                    {  
                        return null;  
                    }  
                    byte[] tmp = new byte[i * 3 + 2];  
                    System.arraycopy(decodedData, 0, tmp, 0, i * 3);  
                    tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);  
                    tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));  
                    return tmp;  
                } else {  
                    return null;  
                }  
            } else { //No PAD e.g 3cQl  
                b3 = base64Alphabet[d3];  
                b4 = base64Alphabet[d4];  
                decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);  
                decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));  
                decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);  
      
            }  
      
            return decodedData;  
        }  
      
        /** 
         * remove WhiteSpace from MIME containing encoded Base64 data. 
         * 
         * @param data  the byte array of base64 data (with WS) 
         * @return      the new length 
         */  
        private static int removeWhiteSpace(char[] data) {  
            if (data == null) {  
                return 0;  
            }  
      
            // count characters that's not whitespace  
            int newSize = 0;  
            int len = data.length;  
            for (int i = 0; i < len; i++) {  
                if (!isWhiteSpace(data[i])) {  
                    data[newSize++] = data[i];  
                }  
            }  
            return newSize;  
        }  
    }  
    package com.zl.test3;
    
    public class MainTest {  
    	  
        public static void main(String[] args) throws Exception {  
            String filepath="F:/javaee/bgyworkspace/Security/doc";  
      
              
              
            System.out.println("--------------公钥加密私钥解密过程-------------------");  
    //        String plainText="ihep_公钥加密私钥解密";  
            String  json="{"
    		  		+ "\"bgyprogressuuid\": \"aabc891fc62f41728497da2904294e16\","
    		  		+ "\"bgysupplier\": \"供应商名称3\","
    				 + " \"bgyitemname\": \"项目公司名称3\","
    				    + "\"bgyitemcode\": \"0003\","
    				    + "\"bgyarea\": \"佛山区域3\","
    				    + "\"bgycontractname\": \"合同名称\","
    				    + "\"bgycontractno\": \"合同编号003\","
    				    + "\"bgypayamount\": 888.989,"
    				    + "\"bgysupplierbank\": \"供应商开户行:中国银行\","
    				    + "\"bgysupplieraccount\": \"供应商账号:88888989989\","
    				    + "\"bgysupplieraccountname\": \"收方户名:佛山碧桂园\","
    				    + "\"bgypaystatus\": false,"
    				    + "\"dr\": 0}"
    				    +"{"
    			  		+ "\"bgyprogressuuid\": \"aabc891fc62f41728497da2904294e15\","
    			  		+ "\"bgysupplier\": \"供应商名称3\","
    					 + " \"bgyitemname\": \"项目公司名称3\","
    					    + "\"bgyitemcode\": \"0003\","
    					    + "\"bgyarea\": \"佛山区域3\","
    					    + "\"bgycontractname\": \"合同名称\","
    					    + "\"bgycontractno\": \"合同编号003\","
    					    + "\"bgypayamount\": 888.989,"
    					    + "\"bgysupplierbank\": \"供应商开户行:中国银行\","
    					    + "\"bgysupplieraccount\": \"供应商账号:88888989989\","
    					    + "\"bgysupplieraccountname\": \"收方户名:佛山碧桂园\","
    					    + "\"bgypaystatus\": false,"
    					    + "\"dr\": 0}";
            //公钥加密过程  
            byte[] cipherData=RSAEncrypt.encrypt(RSAEncrypt.loadPublicKeyByStr(RSAEncrypt.loadPublicKeyByFile(filepath)),json.getBytes());  
            String cipher=Base64.encode(cipherData);  
            //私钥解密过程  
            byte[] res=RSAEncrypt.decrypt(RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadPrivateKeyByFile(filepath)), Base64.decode(cipher));  
            String restr=new String(res);  
            System.out.println("原文:"+json);  
            System.out.println("加密:"+cipher);  
            System.out.println("解密:"+restr);  
            System.out.println();   
              
        }  
    }  
    4.源代码下载地址:其中有3个实例,都是可以运行的,点击打开链接
    http://download.csdn.net/detail/qq_31968809/9777763



    展开全文
  • 对称加密和非对称加密

    千次阅读 2019-06-15 20:36:31
    对称加密就是指,加密解密使用同一个密钥的加密方式。 对称加密的工作过程 发送方使用密钥将明文数据加密成密文,然后发送出去,接收方收到密文后,使用同一个密钥将密文解密成明文读取。 对称加密的优点 加密计算...

    对称加密

    • 什么是对称加密?
      对称加密就是指,加密和解密使用同一个密钥的加密方式。
    • 对称加密的工作过程
      发送方使用密钥将明文数据加密成密文,然后发送出去,接收方收到密文后,使用同一个密钥将密文解密成明文读取。
    • 对称加密的优点
      加密计算量小、速度块,适合对大量数据进行加密的场景。

    常见的对称加密算法有DES、3DES、Blowfish、IDEA、RC4、RC5、RC6和AES。

    对称加密的两大不足

    • 密钥传输问题:如上所说,由于对称加密的加密和解密使用的是同一个密钥,所以对称加密的安全性就不仅仅取决于加密算法本身的强度,更取决于密钥是否被安全的保管,因此加密者如何把密钥安全的传递到解密者手里,就成了对称加密面临的关键问题。(比如,我们客户端肯定不能直接存储对称加密的密钥,因为被反编译之后,密钥就泄露了,数据安全性就得不到保障,所以实际中我们一般都是客户端向服务端请求对称加密的密钥,而且密钥还得用非对称加密加密后再传输。)
    • 密钥管理问题:再者随着密钥数量的增多,密钥的管理问题会逐渐显现出来。比如我们在加密用户的信息时,不可能所有用户都用同一个密钥加密解密吧,这样的话,一旦密钥泄漏,就相当于泄露了所有用户的信息,因此需要为每一个用户单独的生成一个密钥并且管理,这样密钥管理的代价也会非常大。
    AES加密

    AES加密算法就是众多对称加密算法中的一种,它的英文全称是Advanced Encryption Standard,翻译过来是高级加密标准,它是用来替代之前的DES加密算法的。
    AES为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节(每个字节8位)。密钥的长度可以使用128位、192位或256位。密钥的长度不同,推荐加密轮数也不同。如AES-128,也就是密钥的长度为128位,加密轮数为10轮。
    在这里插入图片描述
    关于AES加密,详细可参考博客:
    https://blog.csdn.net/gulang03/article/details/81175854

    非对称加密

    与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(public key)和私有密钥(private key)。

    公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

    非对称密钥加密的使用过程:

    • A要向B发送信息,A和B都要产生一对用于加密和解密的公钥和私钥。
    • A的私钥保密,A的公钥告诉B;B的私钥保密,B的公钥告诉A。
    • A要给B发送信息时,A用B的公钥加密信息,因为A知道B的公钥。
    • A将这个消息发给B(已经用B的公钥加密消息)。
    • B收到这个消息后,B用自己的私钥解密A的消息,其他所有收到这个报文的人都无法解密,因为只有B才有B的私钥。
    • 反过来,B向A发送消息也是一样。

    常见的非对称加密算法有:RSA、ECC(移动设备用)、Diffie-Hellman、El Gamal、DSA(数字签名用)。

    总结

    从上面大家应该可以看出对称加密和非对称加密的区别,下面稍微进行一下总结:

    (1) 对称加密加密与解密使用的是同样的密钥,所以速度快,但由于需要将密钥在网络传输,所以安全性不高。
    (2) 非对称加密使用了一对密钥,公钥与私钥,所以安全性高,但加密与解密速度慢。
    (3) 解决的办法是将对称加密的密钥使用非对称加密的公钥进行加密,然后发送出去,接收方使用私钥进行解密得到对称加密的密钥,然后双方可以使用对称加密来进行沟通。

    参考:
    1.https://www.jianshu.com/p/3840b344b27c?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
    2.https://blog.csdn.net/u013320868/article/details/54090295

    展开全文
  • 对称加密和非对称加密原理

    千次阅读 2019-02-22 19:14:47
    对称加密和对称加密原理 **私钥加密(对称加密 symmetric cryptography):**私钥加密算法使用单个私钥来加密解密数据。由于具有密钥的任意一方都可以使用该密钥解密数据,因此必须保护密钥不被未经授权的代理...

    对称加密和非对称加密原理

    私钥加密(对称加密 symmetric cryptography):私钥加密算法使用单个私钥来加密和解密数据。由于具有密钥的任意一方都可以使用该密钥解密数据,因此必须保护密钥不被未经授权的代理得到。私钥加密又称为对称加密 ,因为同一密钥既用于加密又用于解密。私钥加密算法非常快(与公钥算法相比),特别适用于对较大的数据流执行加密转换。Well-known secret key cryptographic algorithms include the Data Encryption Standard (DES), triple-strength DES (3DES), Rivest Cipher 2 (RC2), and Rivest Cipher 4 (RC4).

    通常,私钥算法(称为块密码)用于一次加密一个数据块。块密码(如 RC2、DES、TripleDES 和 Rijndael)通过加密将 n 字节的输入块转换为加密字节的输出块。如果要加密或解密字节序列,必须逐块进行。由于 n 很小(对于 RC2、DES 和 TripleDES,n = 8 字节;n = 16 [默认值];n = 24;对于 Rijndael,n = 32),因此必须对大于 n 的数据值一次加密一个块。
    基类库中提供的块密码类使用称作密码块链 (CBC) 的链模式,它使用一个密钥和一个初始化向量 (IV) 对数据执行加密转换。对于给定的私钥k,一个不使用初始化向量的简单块密码将把相同的明文输入块加密为同样的密文输出块。如果在明文流中有重复的块,那么在密文流中将存在重复的块。如果未经授权的用户知道有关明文块的结构的任何信息,就可以使用这些信息解密已知的密文块并有可能发现您的密钥。若要克服这个问题,可将上一个块中的信息混合到加密下一个块的过程中。这样,两个相同的明文块的输出就会不同。由于该技术使用上一个块加密下一个块,因此使用了一个 IV 来加密数据的第一个块。使用该系统,未经授权的用户有可能知道的公共消息标头将无法用于对密钥进行反向工程。

    可以危及用此类型密码加密的数据的一个方法是,对每个可能的密钥执行穷举搜索。根据用于执行加密的密钥大小,即使使用最快的计算机执行这种搜索,也极其耗时,因此难以实施。使用较大的密钥大小将使解密更加困难。虽然从理论上说加密不会使对手无法检索加密的数据,但这确实极大增加了这样做的成本。如果执行彻底搜索来检索只在几天内有意义的数据需要花费三个月的时间,那么穷举搜索的方法是不实用的。
    私钥加密的缺点是它假定双方已就密钥和 IV 达成协议,并且互相传达了密钥和 IV 的值。并且,密钥必须对未经授权的用户保密。由于存在这些问题,私钥加密通常与公钥加密一起使用,来秘密地传达密钥和 IV 的值。

    最早、最著名的保密密钥或对称密钥加密算法DES(Data Encryption Standard)/DESede是由IBM公司在70年代发展起来的,并经政府的加密标准筛选后,于1976年11月被美国政府采用,DES随后被美国国家标准局和美国国家标准协会(American National Standard Institute,ANSI)承认。DES使用56位密钥对64位的数据块进行加密,并对64位的数据块进行16轮编码。与每轮编码时,一个48位的"每轮"密钥值由56位的完整密钥得出来。

    .NET 提供以下实现类以提供对称的密钥加密算法:
    • DESCryptoServiceProvider

    • RC2CryptoServiceProvider

    • RijndaelManaged

    • TripleDESCryptoServiceProvider

    公钥加密(不对称加密, RSA, DSA, DH asymmetric cryptography ):公钥加密使用一个必须对未经授权的用户保密的私钥和一个可以对任何人公开的公钥。公钥和私钥都在数学上相关联;用公钥加密的数据只能用私钥解密,而用私钥签名的数据只能用公钥验证。公钥可以提供给任何人;公钥用于对要发送到私钥持有者的数据进行加密。两个密钥对于通信会话都是唯一的。公钥加密算法也称为不对称算法,原因是需要用一个密钥加密数据而需要用另一个密钥来解密数据。对称算法的根本原理就是单向函数,f(a)=b,但是用b很难得到a。
    公钥加密算法使用固定的缓冲区大小,而私钥加密算法使用长度可变的缓冲区。公钥算法无法像私钥算法那样将数据链接起来成为流,原因是它只可以加密少量数据。因此,不对称操作不使用与对称操作相同的流模型。

    双方(小红和小明)可以按照下列方式使用公钥加密。首先,小红生成一个公钥/私钥对。如果小明想要给小红发送一条加密的消息,他将向她索要她的公钥。小红通过不安全的网络将她的公钥发送给小明,小明接着使用该密钥加密消息。(如果小明在不安全的信道如公共网络上收到小红的密钥,则小明必须同小红验证他具有她的公钥的正确副本。)小明将加密的消息发送给小红,而小红使用她的私钥解密该消息。
    但是,在传输小红的公钥期间,未经授权的代理可能截获该密钥。而且,同一代理可能截获来自小明的加密消息。但是,该代理无法用公钥解密该消息。该消息只能用小红的私钥解密,而该私钥没有被传输。小红不使用她的私钥加密给小明的答复消息,原因是任何具有公钥的人都可以解密该消息。如果小红想要将消息发送回小明,她将向小明索要他的公钥并使用该公钥加密她的消息。然后,小明使用与他相关联的私钥来解密该消息。

    在一个实际方案中,小红和小明使用公钥(不对称)加密来传输私(对称)钥,而对他们的会话的其余部分使用私钥加密(由于对称加密快捷,用于实际的数据加密,而利用不对称加密的方式解决对称加密中私钥传递的不安全性,此为对称和不对称加密结合的加密方式)。
    公钥加密具有更大的密钥空间(或密钥的可能值范围),因此不大容易受到对每个可能密钥都进行尝试的穷举攻击。由于不必保护公钥,因此它易于分发。公钥算法可用于创建数字签名以验证数据发送方的身份。但是,公钥算法非常慢(与私钥算法相比),不适合用来加密大量数据。公钥算法仅对传输很少量的数据有用。公钥加密通常用于加密一个私钥算法将要使用的密钥和 IV。传输密钥和 IV 后,会话的其余部分将使用私钥加密。

    RSA系统是诸多此类算法中最著名、最多使用的一种。RSA公开密钥密码系统是由R.Rivest、A.Shamir和L.Adleman俊教授于1977年提出的。RSA的取名就是来自于这三位发明者的姓的第一个字母RSA(Rivest-Shamir-Adleman)算法是基于大数不可能被质因数分解假设的公钥体系。简单地说就是找两个很大的质数。一个对外公开的为“公钥”(Prblic key) ,另一个不告诉任何人,称为"私钥”(Private key)。这两个密钥是互补的,也就是说用公钥加密的密文可以用私钥解密,反过来也一样。

    公钥的传输:要启动安全通讯,通信两端必须首先得到相同的共享密钥(主密钥),但共享密钥不能通过网络相互发送,因为这种做法极易泄密。Diffie-Hellman算法是用于密钥交换的最早最安全的算法之一。

    RSA算法:RSA算法是基于大数难于分解的原理。不但可以用于认证,也可以用于密钥传输,例子可以参考RSAUtil.java文件。那么用户A和B如何利用RSA算法来传输密钥呢?

    1:A产生一个密钥K,用B的公钥加密K,然后将得到的密文发送给B。

    2:B用自己的私钥解密收到的密钥,就可以得到密钥。

    DH算法:DH算法的出现就是用来进行密钥传输的。DH算法是基于离散对数实现的。DH算法的基本工作原理是:通信双方公开或半公开交换一些准备用来生成密钥的"材料数据",在彼此交换过密钥生成"材料"后,两端可以各自生成出完全一样的共享密钥。在任何时候,双方都绝不交换真正的密钥。通信双方交换的密钥生成"材料",长度不等,"材料"长度越长,所生成的密钥强度也就越高,密钥破译就越困难。除进行密钥交换外,IPSec还使用DH算法生成所有其他加密密钥。

    在通信前,用户A和B双方约定2个大整数n和g,其中1<g<n,这两个整数可以公开

    1. A随机产生一个大整数a,然后计算Ka=ga mod n(a需要保密)

    2. B随机产生一个大整数b,然后计算Kb=gb mod n(b需要保密)

    3. A把Ka发送给B,B把Kb发送给A

    4. A计算K=Kba mod n

    5. B计算K=Kab mod n

    由于Kba mod n= (gb mod n)a mod n= (ga mod n)b mod n,因此可以保证双方得到的K是相同的,K即是共享的密钥。可以参考JCE文档中的DH 3 party的例子。

    实际的一个用DH算法传递DES私钥的JAVA例子参看“JAVA上加密算法的实现用例”一文中的末一个例子,过程如下:假设A和B通信(JCE中只支持DH算法作为传递私钥的算法)

    A利用KeyPairGenerator类生成一个钥对类KeyPair并可通过generatePublic方法产生公钥PublicKey(puA)和getPrivate方法私钥PrivateKey(prA)。A把puA发给B。B用类X509EncodedKeySpec解码,然后利用KeyFactory类生成puA,转换成DHPublicKey类利用其getParams方法取得参数类DHParameterSpec,B再利用此参数类,通过KeyPairGenerator类的initialize方法生成KeyPairGenerator实例从而用generateKeyPair方法生成B的KeyPair。进而B生成puB和prB,B把puB发给A。A利用puB和prA作为参数,分别调用KeyAgreement类的init和doPhase方法初始化,然后用generateSecret方法生成各自的DES的密钥SecretKey,此密钥是相同的,即可用Cipher类进行加解密了。

    .NET 通过抽象基类 (System.Security.Crytography.AsymmetricAlgorithm) 提供下列非对称(公钥/私钥)加密算法:
    • DSACryptoServiceProvider

    • RSACryptoServiceProvider

    数字签名
    公钥算法还可用于构成数字签名。数字签名验证发送方的身份(如果您信任发送方的公钥)并帮助保护数据的完整性。

    为了使用公钥加密对消息进行数字签名,小红首先将哈希算法应用于该消息以创建消息摘要。该消息摘要是数据的紧凑且唯一的表示形式。然后,小红用她的私钥加密该消息摘要以创建她的个人签名。在收到消息和签名时,小明使用小红的公钥解密签名以恢复消息摘要,并使用与小红所使用的相同的哈希算法来散列消息。如果小明计算的消息摘要与从小红那里收到的消息摘要完全一致,小明就可以确定该消息来自私钥的持有人,并且数据未被修改过。如果小明相信小红是私钥的持有人,则他知道该消息来自小红。

    请注意,由于发送方的公钥为大家所周知,并且它通常包含在数字签名格式中,因此任何人都可以验证签名。此方法不保守消息的机密;若要使消息保密,还必须对消息进行加密。

    .NET Framework 提供以下实现数字签名算法的类:

    DSACryptoServiceProvider
    RSACryptoServiceProvider

    CA证书 Public Key Certificates(参考这里)

    A public key certificate provides a safe way for an entity to pass on its public key to be used in asymmetric cryptography. The public key certificate avoids the following situation: if Charlie creates his own public key and private key, he can claim that he is Alice and send his public key to Bob. Bob will be able to communicate with Charlie, but Bob will think that he is sending his data to Alice.

    A public key certificate can be thought of as the digital equivalent of a passport. It is issued by a trusted organization and provides identification for the bearer. A trusted organization that issues public key certificates is known as a certificate authority (CA). The CA can be likened to a notary public. To obtain a certificate from a CA, one must provide proof of identity. Once the CA is confident that the applicant represents the organization it says it represents, the CA signs the certificate attesting to the validity of the information contained within the certificate.

    A public key certificate contains several fields, including:

    Issuer - The issuer is the CA that issued the certificate. If a user trusts the CA that issues a certificate, and if the certificate is valid, the user can trust the certificate.

    Period of validity - A certificate has an expiration date, and this date is one piece of information that should be checked when verifying the validity of a certificate.

    Subject - The subject field includes information about the entity that the certificate represents.

    Subject’s public key - The primary piece of information that the certificate provides is the subject’s public key. All the other fields are provided to ensure the validity of this key.

    Signature - The certificate is digitally signed by the CA that issued the certificate. The signature is created using the CA’s private key and ensures the validity of the certificate. Because only the certificate is signed, not the data sent in the SSL transaction, SSL does not provide for non-repudiation.
    If Bob only accepts Alice’s public key as valid when she sends it in a public key certificate, Bob will not be fooled into sending secret information to Charlie when Charlie masquerades as Alice.

    Multiple certificates may be linked in a certificate chain. When a certificate chain is used, the first certificate is always that of the sender. The next is the certificate of the entity that issued the sender’s certificate. If there are more certificates in the chain, each is that of the authority that issued the previous certificate. The final certificate in the chain is the certificate for a root CA. A root CA is a public certificate authority that is widely trusted. Information for several root CAs is typically stored in the client’s Internet browser. This information includes the CA’s public key. Well-known CAs include VeriSign, Entrust, and GTE CyberTrust.

    哈希值
    哈希算法将任意长度的二进制值映射为固定长度的较小二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希计算都将产生不同的值。要找到散列为同一个值的两个不同的输入,在计算上是不可能的。

    消息身份验证代码 (MAC) 哈希函数通常与数字签名一起用于对数据进行签名,而消息检测代码 (MDC) 哈希函数则用于数据完整性。

    双方(小红和小明)可按下面的方式使用哈希函数来确保数据的完整性。如果小红对小明编写一条消息并创建该消息的哈希,则小明可以在稍后散列该消息并将他的哈希与原始哈希进行比较。如果两个哈希值相同,则该消息没有被更改;如果值不相同,则该消息在小红编写它之后已被更改。为了使此系统发挥作用,小红必须对除小明外的所有人保密原始的哈希值。

    When sending encrypted data, SSL typically uses a cryptographic hash function to ensure data integrity. The hash function prevents Charlie from tampering with data that Alice sends to Bob.

    A cryptographic hash function is similar to a checksum. The main difference is that while a checksum is designed to detect accidental alterations in data, a cryptographic hash function is designed to detect deliberate alterations. When data is processed by a cryptographic hash function, a small string of bits, known as a hash, is generated. The slightest change to the message typically makes a large change in the resulting hash. A cryptographic hash function does not require a cryptographic key. Two hash functions often used with SSL are Message Digest 5 (MD5) and Secure Hash Algorithm (SHA). SHA was proposed by the US National Institute of Science and Technology (NIST).

    Message Authentication Code: A message authentication code (MAC) is similar to a cryptographic hash, except that it is based on a secret key. When secret key information is included with the data that is processed by a cryptographic hash function, the resulting hash is known as an HMAC.
    If Alice wants to be sure that Charlie does not tamper with her message to Bob, she can calculate an HMAC for her message and append the HMAC to her original message. She can then encrypt the message plus the HMAC using a secret key she shares with Bob. When Bob decrypts the message and calculates the HMAC, he will be able to tell if the message was modified in transit. With SSL, an HMAC is used with the transmission of secure data.

    .NET Framework 提供以下实现数字签名算法的类:

    HMACSHA1
    MACTripleDES
    MD5CryptoServiceProvider
    SHA1Managed
    SHA256Managed
    SHA384Managed
    SHA512Managed

    摘要函数(MD2、MD4和MD5,还有SHA1等算法(产生一个20字节的二进制数组))
    摘要是一种防止改动的方法,其中用到的函数叫摘要函数。这些函数的输入可以是任意大小的消息,而输出是一个固定长度的摘要。摘要有这样一个性质,如果改变了输入消息中的任何东西,甚至只有一位,输出的摘要将会发生不可预测的改变,也就是说输入消息的每一位对输出摘要都有影响。总之,摘要算法从给定的文本块中产生一个数字签名(fingerprint或message digest),数字签名可以用于防止有人从一个签名上获取文本信息或改变文本信息内容。摘要算法的数字签名原理在很多加密算法中都被使用,如S/KEY和PGP(pretty good privacy)。

    现在流行的摘要函数有MD4和MD5。MD2摘要算法的设计是出于下面的考虑:利用32位RISC结构来最大其吞吐量,而不需要大量的替换表(substitution table)。MD4算法将消息的给予对长度作为输入,产生一个128位的"指纹"或"消息化"。要产生两个具有相同消息化的文字块或者产生任何具有预先给定"指纹"的消息,都被认为在计算上是不可能的。MD5摘要算法是个数据认证标准。MD5的设计思想是要找出速度更快但更不安全的MD4中潜在的不安全,MD5的设计者通过使MD5在计算上慢下来,以及对这些计算做了一些基础性的改动来解决这个问题。MD5在RFC1321中给出文档描述,是MD4算法的一个扩展。美国国家标准技术研究所的SHA1和麻省理工学院Ronald Rivest提出的MD5是为代表。HMAC-MD5算法(消息摘要5)基于RFC1321。MD5对MD4做了改进,计算速度比MD4稍慢,但安全性能得到了进一步改善。MD5在计算中使用了64个32位常数,最终生成一个128位的完整性检查和。

    HMAC-SHA算法:安全Hash算法定义在NIST FIPS 180-1,其算法以MD5为原型。SHA在计算中使用了79个32位常数,最终产生一个160位完整性检查和。SHA检查和长度比MD5更长,因此安全性也更高。

    随机数生成
    随机数生成是许多加密操作不可分割的组成部分。例如,加密密钥需要尽可能地随机,以便使生成的密钥很难再现。加密随机数生成器必须生成无法以计算方法推算出(低于 p < .05 的概率)的输出;即,任何推算下一个输出位的方法不得比随机猜测具有更高的成功概率。.NET Framework 中的类使用随机数生成器生成加密密钥。

    在商务领域的应用

    许多人都知道NETSCAPE公司是Internet商业中领先技术的提供者,该公司提供了一种基于RSA和保密密钥的应用于因特网的技术,被称为安全插座层(Secure Sockets Layer,SSL)。

    也许很多人知道Socket,它是一个编程界面,并不提供任何安全措施,而SSL不但提供编程界面,而且向上提供一种安全的服务,SSL3.0现在已经应用到了服务器和浏览器上,SSL2.0则只能应用于服务器端。

    SSL3.0用一种电子证书(electric certificate)来实行身份进行验证后,双方就可以用保密密钥进行安全的会话了。它同时使用“对称”和“非对称”加密方法,在客户与电子商务的服务器进行沟通的过程中,客户会产生一个Session Key,然后客户用服务器端的公钥将Session Key进行加密,再传给服务器端,在双方都知道Session Key后,传输的数据都是以Session Key进行加密与解密的,但服务器端发给用户的公钥必需先向有关发证机关申请,以得到公证。

    基于SSL3.0提供的安全保障,用户就可以自由订购商品并且给出信用卡号了,也可以在网上和合作伙伴交流商业信息并且让供应商把订单和收货单从网上发过来,这样可以节省大量的纸张,为公司节省大量的电话、传真费用。在过去,电子信息交换(Electric Data Interchange,EDI)、信息交易(information transaction)和金融交易(financial transaction)都是在专用网络上完成的,使用专用网的费用大大高于互联网。正是这样巨大的诱惑,才使人们开始发展因特网上的电子商务,但不要忘记数据加密。

    SSL(Secure Sockets Layer) or TSL (Transport Layer Security)

    Secure Sockets Layer (SSL) is the most widely used protocol for implementing cryptography on the Web. SSL uses a combination of cryptographic processes to provide secure communication over a network. This section provides an introduction to SSL and the cryptographic processes it uses.

    SSL provides a secure enhancement to the standard TCP/IP sockets protocol used for Internet communications. As shown in the “TCP/IP Protocol Stack With SSL” figure below, the secure sockets layer is added between the transport layer and the application layer in the standard TCP/IP protocol stack. The application most commonly used with SSL is Hypertext Transfer Protocol (HTTP), the protocol for Internet Web pages.

    SSL was developed by Netscape in 1994, and with input from the Internet community, has evolved to become a standard. It is now under the control of the international standards organization, the Internet Engineering Task Force (IETF). The IETF has renamed SSL to Transport Layer Security (TLS), and released the first specification, version 1.0, in January 1999. TLS 1.0 is a modest upgrade to the most recent version of SSL, version 3.0. The differences between SSL 3.0 and TLS 1.0 are minor.

    One of the reasons SSL is effective is that it uses several different cryptographic processes. SSL uses public key cryptography to provide authentication, and secret key cryptography and digital signatures to provide for privacy and data integrity. Before you can understand SSL, it is helpful to understand these cryptographic processes.

    常用算法比较

    数据加密标准(DES)是一个古老的对称密钥加密算法,目前已经不再使用。它不是一个很安全的算法。

    三重DES(Triple-DES)仍然是很安全的,但是也只是在别无他法的情况下的一个较好的选择。显然高级加密标准(AES)是一个更好的加密算法,NIST用AES代替Triple-DES作为他们的标准(下面有更详细的讨论)。其他较好的算法包括另外两个AES的变种算法Twofish和Serpent-也称为CAST-128,它是效率和安全的完美结合。这几个算法不仅比DES更安全,而且也比DES的速度更快。为什么要使用一些又慢又不安全的算法呢

    SHA1是一个哈希函数,而不是一个加密函数。作为一个哈希函数,SHA1还是相当优秀的,但是还需要几年的发展才能用作加密算法。如果你正在设计一个新系统,那么谨记你可能会在若干年后用SHA1代替目前的算法。我再重复一遍:只是可能。

    RSA是一个公开密钥加密算法。RSA的密钥长度一般为2048-4096位。如果你现在的系统使用的是1024位的公开密钥,也没有必要担心,但是你可以加长密钥长度来达到更好的加密效果。

    高级加密标准(AES)是一个用来代替数据加密标准(DES)的算法。目前使用的一般为128,196和256位密钥,这三种密钥都是相当安全的。而且美国政府也是这样认为的。他们批准将128位密钥的AES算法用于一般数据加密,196位和256位密钥的AES算法用于秘密数据和绝密数据的加密。

    DESX是DES的一个改进版本。DESX的原理是利用一个随机的二进制数与加密前的数据以及解密后的数据异或。虽然也有人批评这种算法,但是与DES相比DESX确实更安全,不过DESX在许多情况下并不适用。我曾经处理过一个硬件支持DES的系统,由于有些环节不能容忍三重DES的慢速,我们在这些地方使用了DESX来代替DES。然而,这是一个非常特殊的情况。如果你需要使用DESX,理由显而易见(可能和我不得不使用DESX的原因类似)。但我建议你使用AES或者上面我提到的一些算法。

    RC4是一种常用于SSL连接的数据流加密算法。它已经出现很多年了,而且有很多已知和可能的缺陷,因此在一些新的工程中不要使用它。如果你目前正在使用它而且可以轻易的卸载它,那么情况也不是很坏。不过,我怀疑如果你现在正在使用它,你不可能轻易的卸载它。如果不能将它从系统中轻易的卸载,那么你还是考虑今后怎样升级它,但是不要感到很惊慌。我不会拒绝在一个使用RC4算法来加密SSL连接的网站购买东西,但是如果我现在要新建一个系统,那么我会考虑使用其他的算法,例如:AES。

    对于下面两个算法MD5-RSA和SHA1-DSA,他们是用于数字签名的。但是不要使用MD5,因为它有很多缺陷。很多年前大家就知道MD5中存在漏洞,不过直到今年夏天才破解出来。我们可以将SHA1和RSA或DSA配合在一起使用,目前DSA的密钥位数高达1024位,这个密钥位数已经足够长了,因此不需要担心安全问题。然而,如果NIST实现了更长的密钥位数当然更好。

    X.509证书是一个数据结构,常用于规定比特和字节的顺序,它本身不是一个密码系统。它通常包含一个RSA密钥,也可能包含一个DSA密钥。但是X.509证书内部以及证书本身并不是加密技术。对称加密和不对称加密原理
    私钥加密(对称加密 symmetric cryptography):私钥加密算法使用单个私钥来加密和解密数据。由于具有密钥的任意一方都可以使用该密钥解密数据,因此必须保护密钥不被未经授权的代理得到。私钥加密又称为对称加密,因为同一密钥既用于加密又用于解密。私钥加密算法非常快(与公钥算法相比),特别适用于对较大的数据流执行加密转换。Well-known secret key cryptographic algorithms include the Data Encryption Standard (DES), triple-strength DES (3DES), Rivest Cipher 2 (RC2), and Rivest Cipher 4 (RC4).

    通常,私钥算法(称为块密码)用于一次加密一个数据块。块密码(如 RC2、DES、TripleDES 和 Rijndael)通过加密将 n 字节的输入块转换为加密字节的输出块。如果要加密或解密字节序列,必须逐块进行。由于 n 很小(对于 RC2、DES 和 TripleDES,n = 8 字节;n = 16 [默认值];n = 24;对于 Rijndael,n = 32),因此必须对大于 n 的数据值一次加密一个块。
    基类库中提供的块密码类使用称作密码块链 (CBC) 的链模式,它使用一个密钥和一个初始化向量 (IV) 对数据执行加密转换。对于给定的私钥k,一个不使用初始化向量的简单块密码将把相同的明文输入块加密为同样的密文输出块。如果在明文流中有重复的块,那么在密文流中将存在重复的块。如果未经授权的用户知道有关明文块的结构的任何信息,就可以使用这些信息解密已知的密文块并有可能发现您的密钥。若要克服这个问题,可将上一个块中的信息混合到加密下一个块的过程中。这样,两个相同的明文块的输出就会不同。由于该技术使用上一个块加密下一个块,因此使用了一个 IV 来加密数据的第一个块。使用该系统,未经授权的用户有可能知道的公共消息标头将无法用于对密钥进行反向工程。

    可以危及用此类型密码加密的数据的一个方法是,对每个可能的密钥执行穷举搜索。根据用于执行加密的密钥大小,即使使用最快的计算机执行这种搜索,也极其耗时,因此难以实施。使用较大的密钥大小将使解密更加困难。虽然从理论上说加密不会使对手无法检索加密的数据,但这确实极大增加了这样做的成本。如果执行彻底搜索来检索只在几天内有意义的数据需要花费三个月的时间,那么穷举搜索的方法是不实用的。
    私钥加密的缺点是它假定双方已就密钥和 IV 达成协议,并且互相传达了密钥和 IV 的值。并且,密钥必须对未经授权的用户保密。由于存在这些问题,私钥加密通常与公钥加密一起使用,来秘密地传达密钥和 IV 的值。

    最早、最著名的保密密钥或对称密钥加密算法DES(Data Encryption Standard)/DESede是由IBM公司在70年代发展起来的,并经政府的加密标准筛选后,于1976年11月被美国政府采用,DES随后被美国国家标准局和美国国家标准协会(American National Standard Institute,ANSI)承认。DES使用56位密钥对64位的数据块进行加密,并对64位的数据块进行16轮编码。与每轮编码时,一个48位的"每轮"密钥值由56位的完整密钥得出来。

    .NET 提供以下实现类以提供对称的密钥加密算法:
    • DESCryptoServiceProvider

    • RC2CryptoServiceProvider

    • RijndaelManaged

    • TripleDESCryptoServiceProvider

    公钥加密(不对称加密, RSA, DSA, DH asymmetric cryptography ):公钥加密使用一个必须对未经授权的用户保密的私钥和一个可以对任何人公开的公钥。公钥和私钥都在数学上相关联;用公钥加密的数据只能用私钥解密,而用私钥签名的数据只能用公钥验证。公钥可以提供给任何人;公钥用于对要发送到私钥持有者的数据进行加密。两个密钥对于通信会话都是唯一的。公钥加密算法也称为不对称算法,原因是需要用一个密钥加密数据而需要用另一个密钥来解密数据。对称算法的根本原理就是单向函数,f(a)=b,但是用b很难得到a。
    公钥加密算法使用固定的缓冲区大小,而私钥加密算法使用长度可变的缓冲区。公钥算法无法像私钥算法那样将数据链接起来成为流,原因是它只可以加密少量数据。因此,不对称操作不使用与对称操作相同的流模型。

    双方(小红和小明)可以按照下列方式使用公钥加密。首先,小红生成一个公钥/私钥对。如果小明想要给小红发送一条加密的消息,他将向她索要她的公钥。小红通过不安全的网络将她的公钥发送给小明,小明接着使用该密钥加密消息。(如果小明在不安全的信道如公共网络上收到小红的密钥,则小明必须同小红验证他具有她的公钥的正确副本。)小明将加密的消息发送给小红,而小红使用她的私钥解密该消息。
    但是,在传输小红的公钥期间,未经授权的代理可能截获该密钥。而且,同一代理可能截获来自小明的加密消息。但是,该代理无法用公钥解密该消息。该消息只能用小红的私钥解密,而该私钥没有被传输。小红不使用她的私钥加密给小明的答复消息,原因是任何具有公钥的人都可以解密该消息。如果小红想要将消息发送回小明,她将向小明索要他的公钥并使用该公钥加密她的消息。然后,小明使用与他相关联的私钥来解密该消息。

    在一个实际方案中,小红和小明使用公钥(不对称)加密来传输私(对称)钥,而对他们的会话的其余部分使用私钥加密(由于对称加密快捷,用于实际的数据加密,而利用不对称加密的方式解决对称加密中私钥传递的不安全性,此为对称和不对称加密结合的加密方式)。
    公钥加密具有更大的密钥空间(或密钥的可能值范围),因此不大容易受到对每个可能密钥都进行尝试的穷举攻击。由于不必保护公钥,因此它易于分发。公钥算法可用于创建数字签名以验证数据发送方的身份。但是,公钥算法非常慢(与私钥算法相比),不适合用来加密大量数据。公钥算法仅对传输很少量的数据有用。公钥加密通常用于加密一个私钥算法将要使用的密钥和 IV。传输密钥和 IV 后,会话的其余部分将使用私钥加密。

    RSA系统是诸多此类算法中最著名、最多使用的一种。RSA公开密钥密码系统是由R.Rivest、A.Shamir和L.Adleman俊教授于1977年提出的。RSA的取名就是来自于这三位发明者的姓的第一个字母RSA(Rivest-Shamir-Adleman)算法是基于大数不可能被质因数分解假设的公钥体系。简单地说就是找两个很大的质数。一个对外公开的为“公钥”(Prblic key) ,另一个不告诉任何人,称为"私钥”(Private key)。这两个密钥是互补的,也就是说用公钥加密的密文可以用私钥解密,反过来也一样。

    公钥的传输:要启动安全通讯,通信两端必须首先得到相同的共享密钥(主密钥),但共享密钥不能通过网络相互发送,因为这种做法极易泄密。Diffie-Hellman算法是用于密钥交换的最早最安全的算法之一。

    RSA算法:RSA算法是基于大数难于分解的原理。不但可以用于认证,也可以用于密钥传输,例子可以参考RSAUtil.java文件。那么用户A和B如何利用RSA算法来传输密钥呢?

    1:A产生一个密钥K,用B的公钥加密K,然后将得到的密文发送给B。

    2:B用自己的私钥解密收到的密钥,就可以得到密钥。

    DH算法:DH算法的出现就是用来进行密钥传输的。DH算法是基于离散对数实现的。DH算法的基本工作原理是:通信双方公开或半公开交换一些准备用来生成密钥的"材料数据",在彼此交换过密钥生成"材料"后,两端可以各自生成出完全一样的共享密钥。在任何时候,双方都绝不交换真正的密钥。通信双方交换的密钥生成"材料",长度不等,"材料"长度越长,所生成的密钥强度也就越高,密钥破译就越困难。除进行密钥交换外,IPSec还使用DH算法生成所有其他加密密钥。

    在通信前,用户A和B双方约定2个大整数n和g,其中1<g<n,这两个整数可以公开

    1. A随机产生一个大整数a,然后计算Ka=ga mod n(a需要保密)

    2. B随机产生一个大整数b,然后计算Kb=gb mod n(b需要保密)

    3. A把Ka发送给B,B把Kb发送给A

    4. A计算K=Kba mod n

    5. B计算K=Kab mod n

    由于Kba mod n= (gb mod n)a mod n= (ga mod n)b mod n,因此可以保证双方得到的K是相同的,K即是共享的密钥。可以参考JCE文档中的DH 3 party的例子。

    实际的一个用DH算法传递DES私钥的JAVA例子参看“JAVA上加密算法的实现用例”一文中的末一个例子,过程如下:假设A和B通信(JCE中只支持DH算法作为传递私钥的算法)

    A利用KeyPairGenerator类生成一个钥对类KeyPair并可通过generatePublic方法产生公钥PublicKey(puA)和getPrivate方法私钥PrivateKey(prA)。A把puA发给B。B用类X509EncodedKeySpec解码,然后利用KeyFactory类生成puA,转换成DHPublicKey类利用其getParams方法取得参数类DHParameterSpec,B再利用此参数类,通过KeyPairGenerator类的initialize方法生成KeyPairGenerator实例从而用generateKeyPair方法生成B的KeyPair。进而B生成puB和prB,B把puB发给A。A利用puB和prA作为参数,分别调用KeyAgreement类的init和doPhase方法初始化,然后用generateSecret方法生成各自的DES的密钥SecretKey,此密钥是相同的,即可用Cipher类进行加解密了。

    .NET 通过抽象基类 (System.Security.Crytography.AsymmetricAlgorithm) 提供下列非对称(公钥/私钥)加密算法:
    • DSACryptoServiceProvider

    • RSACryptoServiceProvider

    数字签名
    公钥算法还可用于构成数字签名。数字签名验证发送方的身份(如果您信任发送方的公钥)并帮助保护数据的完整性。

    为了使用公钥加密对消息进行数字签名,小红首先将哈希算法应用于该消息以创建消息摘要。该消息摘要是数据的紧凑且唯一的表示形式。然后,小红用她的私钥加密该消息摘要以创建她的个人签名。在收到消息和签名时,小明使用小红的公钥解密签名以恢复消息摘要,并使用与小红所使用的相同的哈希算法来散列消息。如果小明计算的消息摘要与从小红那里收到的消息摘要完全一致,小明就可以确定该消息来自私钥的持有人,并且数据未被修改过。如果小明相信小红是私钥的持有人,则他知道该消息来自小红。

    请注意,由于发送方的公钥为大家所周知,并且它通常包含在数字签名格式中,因此任何人都可以验证签名。此方法不保守消息的机密;若要使消息保密,还必须对消息进行加密。

    .NET Framework 提供以下实现数字签名算法的类:

    DSACryptoServiceProvider
    RSACryptoServiceProvider

    CA证书 Public Key Certificates(参考这里)

    A public key certificate provides a safe way for an entity to pass on its public key to be used in asymmetric cryptography. The public key certificate avoids the following situation: if Charlie creates his own public key and private key, he can claim that he is Alice and send his public key to Bob. Bob will be able to communicate with Charlie, but Bob will think that he is sending his data to Alice.

    A public key certificate can be thought of as the digital equivalent of a passport. It is issued by a trusted organization and provides identification for the bearer. A trusted organization that issues public key certificates is known as a certificate authority (CA). The CA can be likened to a notary public. To obtain a certificate from a CA, one must provide proof of identity. Once the CA is confident that the applicant represents the organization it says it represents, the CA signs the certificate attesting to the validity of the information contained within the certificate.

    A public key certificate contains several fields, including:

    Issuer - The issuer is the CA that issued the certificate. If a user trusts the CA that issues a certificate, and if the certificate is valid, the user can trust the certificate.

    Period of validity - A certificate has an expiration date, and this date is one piece of information that should be checked when verifying the validity of a certificate.

    Subject - The subject field includes information about the entity that the certificate represents.

    Subject’s public key - The primary piece of information that the certificate provides is the subject’s public key. All the other fields are provided to ensure the validity of this key.

    Signature - The certificate is digitally signed by the CA that issued the certificate. The signature is created using the CA’s private key and ensures the validity of the certificate. Because only the certificate is signed, not the data sent in the SSL transaction, SSL does not provide for non-repudiation.
    If Bob only accepts Alice’s public key as valid when she sends it in a public key certificate, Bob will not be fooled into sending secret information to Charlie when Charlie masquerades as Alice.

    Multiple certificates may be linked in a certificate chain. When a certificate chain is used, the first certificate is always that of the sender. The next is the certificate of the entity that issued the sender’s certificate. If there are more certificates in the chain, each is that of the authority that issued the previous certificate. The final certificate in the chain is the certificate for a root CA. A root CA is a public certificate authority that is widely trusted. Information for several root CAs is typically stored in the client’s Internet browser. This information includes the CA’s public key. Well-known CAs include VeriSign, Entrust, and GTE CyberTrust.

    哈希值
    哈希算法将任意长度的二进制值映射为固定长度的较小二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希计算都将产生不同的值。要找到散列为同一个值的两个不同的输入,在计算上是不可能的。

    消息身份验证代码 (MAC) 哈希函数通常与数字签名一起用于对数据进行签名,而消息检测代码 (MDC) 哈希函数则用于数据完整性。

    双方(小红和小明)可按下面的方式使用哈希函数来确保数据的完整性。如果小红对小明编写一条消息并创建该消息的哈希,则小明可以在稍后散列该消息并将他的哈希与原始哈希进行比较。如果两个哈希值相同,则该消息没有被更改;如果值不相同,则该消息在小红编写它之后已被更改。为了使此系统发挥作用,小红必须对除小明外的所有人保密原始的哈希值。

    When sending encrypted data, SSL typically uses a cryptographic hash function to ensure data integrity. The hash function prevents Charlie from tampering with data that Alice sends to Bob.

    A cryptographic hash function is similar to a checksum. The main difference is that while a checksum is designed to detect accidental alterations in data, a cryptographic hash function is designed to detect deliberate alterations. When data is processed by a cryptographic hash function, a small string of bits, known as a hash, is generated. The slightest change to the message typically makes a large change in the resulting hash. A cryptographic hash function does not require a cryptographic key. Two hash functions often used with SSL are Message Digest 5 (MD5) and Secure Hash Algorithm (SHA). SHA was proposed by the US National Institute of Science and Technology (NIST).

    Message Authentication Code: A message authentication code (MAC) is similar to a cryptographic hash, except that it is based on a secret key. When secret key information is included with the data that is processed by a cryptographic hash function, the resulting hash is known as an HMAC.
    If Alice wants to be sure that Charlie does not tamper with her message to Bob, she can calculate an HMAC for her message and append the HMAC to her original message. She can then encrypt the message plus the HMAC using a secret key she shares with Bob. When Bob decrypts the message and calculates the HMAC, he will be able to tell if the message was modified in transit. With SSL, an HMAC is used with the transmission of secure data.

    .NET Framework 提供以下实现数字签名算法的类:

    HMACSHA1
    MACTripleDES
    MD5CryptoServiceProvider
    SHA1Managed
    SHA256Managed
    SHA384Managed
    SHA512Managed

    摘要函数(MD2、MD4和MD5,还有SHA1等算法(产生一个20字节的二进制数组))
    摘要是一种防止改动的方法,其中用到的函数叫摘要函数。这些函数的输入可以是任意大小的消息,而输出是一个固定长度的摘要。摘要有这样一个性质,如果改变了输入消息中的任何东西,甚至只有一位,输出的摘要将会发生不可预测的改变,也就是说输入消息的每一位对输出摘要都有影响。总之,摘要算法从给定的文本块中产生一个数字签名(fingerprint或message digest),数字签名可以用于防止有人从一个签名上获取文本信息或改变文本信息内容。摘要算法的数字签名原理在很多加密算法中都被使用,如S/KEY和PGP(pretty good privacy)。

    现在流行的摘要函数有MD4和MD5。MD2摘要算法的设计是出于下面的考虑:利用32位RISC结构来最大其吞吐量,而不需要大量的替换表(substitution table)。MD4算法将消息的给予对长度作为输入,产生一个128位的"指纹"或"消息化"。要产生两个具有相同消息化的文字块或者产生任何具有预先给定"指纹"的消息,都被认为在计算上是不可能的。MD5摘要算法是个数据认证标准。MD5的设计思想是要找出速度更快但更不安全的MD4中潜在的不安全,MD5的设计者通过使MD5在计算上慢下来,以及对这些计算做了一些基础性的改动来解决这个问题。MD5在RFC1321中给出文档描述,是MD4算法的一个扩展。美国国家标准技术研究所的SHA1和麻省理工学院Ronald Rivest提出的MD5是为代表。HMAC-MD5算法(消息摘要5)基于RFC1321。MD5对MD4做了改进,计算速度比MD4稍慢,但安全性能得到了进一步改善。MD5在计算中使用了64个32位常数,最终生成一个128位的完整性检查和。

    HMAC-SHA算法:安全Hash算法定义在NIST FIPS 180-1,其算法以MD5为原型。SHA在计算中使用了79个32位常数,最终产生一个160位完整性检查和。SHA检查和长度比MD5更长,因此安全性也更高。

    随机数生成
    随机数生成是许多加密操作不可分割的组成部分。例如,加密密钥需要尽可能地随机,以便使生成的密钥很难再现。加密随机数生成器必须生成无法以计算方法推算出(低于 p < .05 的概率)的输出;即,任何推算下一个输出位的方法不得比随机猜测具有更高的成功概率。.NET Framework 中的类使用随机数生成器生成加密密钥。

    在商务领域的应用

    许多人都知道NETSCAPE公司是Internet商业中领先技术的提供者,该公司提供了一种基于RSA和保密密钥的应用于因特网的技术,被称为安全插座层(Secure Sockets Layer,SSL)。

    也许很多人知道Socket,它是一个编程界面,并不提供任何安全措施,而SSL不但提供编程界面,而且向上提供一种安全的服务,SSL3.0现在已经应用到了服务器和浏览器上,SSL2.0则只能应用于服务器端。

    SSL3.0用一种电子证书(electric certificate)来实行身份进行验证后,双方就可以用保密密钥进行安全的会话了。它同时使用“对称”和“非对称”加密方法,在客户与电子商务的服务器进行沟通的过程中,客户会产生一个Session Key,然后客户用服务器端的公钥将Session Key进行加密,再传给服务器端,在双方都知道Session Key后,传输的数据都是以Session Key进行加密与解密的,但服务器端发给用户的公钥必需先向有关发证机关申请,以得到公证。

    基于SSL3.0提供的安全保障,用户就可以自由订购商品并且给出信用卡号了,也可以在网上和合作伙伴交流商业信息并且让供应商把订单和收货单从网上发过来,这样可以节省大量的纸张,为公司节省大量的电话、传真费用。在过去,电子信息交换(Electric Data Interchange,EDI)、信息交易(information transaction)和金融交易(financial transaction)都是在专用网络上完成的,使用专用网的费用大大高于互联网。正是这样巨大的诱惑,才使人们开始发展因特网上的电子商务,但不要忘记数据加密。

    SSL(Secure Sockets Layer) or TSL (Transport Layer Security)

    Secure Sockets Layer (SSL) is the most widely used protocol for implementing cryptography on the Web. SSL uses a combination of cryptographic processes to provide secure communication over a network. This section provides an introduction to SSL and the cryptographic processes it uses.

    SSL provides a secure enhancement to the standard TCP/IP sockets protocol used for Internet communications. As shown in the “TCP/IP Protocol Stack With SSL” figure below, the secure sockets layer is added between the transport layer and the application layer in the standard TCP/IP protocol stack. The application most commonly used with SSL is Hypertext Transfer Protocol (HTTP), the protocol for Internet Web pages.

    SSL was developed by Netscape in 1994, and with input from the Internet community, has evolved to become a standard. It is now under the control of the international standards organization, the Internet Engineering Task Force (IETF). The IETF has renamed SSL to Transport Layer Security (TLS), and released the first specification, version 1.0, in January 1999. TLS 1.0 is a modest upgrade to the most recent version of SSL, version 3.0. The differences between SSL 3.0 and TLS 1.0 are minor.

    One of the reasons SSL is effective is that it uses several different cryptographic processes. SSL uses public key cryptography to provide authentication, and secret key cryptography and digital signatures to provide for privacy and data integrity. Before you can understand SSL, it is helpful to understand these cryptographic processes.

    常用算法比较

    数据加密标准(DES)是一个古老的对称密钥加密算法,目前已经不再使用。它不是一个很安全的算法。

    三重DES(Triple-DES)仍然是很安全的,但是也只是在别无他法的情况下的一个较好的选择。显然高级加密标准(AES)是一个更好的加密算法,NIST用AES代替Triple-DES作为他们的标准(下面有更详细的讨论)。其他较好的算法包括另外两个AES的变种算法Twofish和Serpent-也称为CAST-128,它是效率和安全的完美结合。这几个算法不仅比DES更安全,而且也比DES的速度更快。为什么要使用一些又慢又不安全的算法呢

    SHA1是一个哈希函数,而不是一个加密函数。作为一个哈希函数,SHA1还是相当优秀的,但是还需要几年的发展才能用作加密算法。如果你正在设计一个新系统,那么谨记你可能会在若干年后用SHA1代替目前的算法。我再重复一遍:只是可能。

    RSA是一个公开密钥加密算法。RSA的密钥长度一般为2048-4096位。如果你现在的系统使用的是1024位的公开密钥,也没有必要担心,但是你可以加长密钥长度来达到更好的加密效果。

    高级加密标准(AES)是一个用来代替数据加密标准(DES)的算法。目前使用的一般为128,196和256位密钥,这三种密钥都是相当安全的。而且美国政府也是这样认为的。他们批准将128位密钥的AES算法用于一般数据加密,196位和256位密钥的AES算法用于秘密数据和绝密数据的加密。

    DESX是DES的一个改进版本。DESX的原理是利用一个随机的二进制数与加密前的数据以及解密后的数据异或。虽然也有人批评这种算法,但是与DES相比DESX确实更安全,不过DESX在许多情况下并不适用。我曾经处理过一个硬件支持DES的系统,由于有些环节不能容忍三重DES的慢速,我们在这些地方使用了DESX来代替DES。然而,这是一个非常特殊的情况。如果你需要使用DESX,理由显而易见(可能和我不得不使用DESX的原因类似)。但我建议你使用AES或者上面我提到的一些算法。

    RC4是一种常用于SSL连接的数据流加密算法。它已经出现很多年了,而且有很多已知和可能的缺陷,因此在一些新的工程中不要使用它。如果你目前正在使用它而且可以轻易的卸载它,那么情况也不是很坏。不过,我怀疑如果你现在正在使用它,你不可能轻易的卸载它。如果不能将它从系统中轻易的卸载,那么你还是考虑今后怎样升级它,但是不要感到很惊慌。我不会拒绝在一个使用RC4算法来加密SSL连接的网站购买东西,但是如果我现在要新建一个系统,那么我会考虑使用其他的算法,例如:AES。

    对于下面两个算法MD5-RSA和SHA1-DSA,他们是用于数字签名的。但是不要使用MD5,因为它有很多缺陷。很多年前大家就知道MD5中存在漏洞,不过直到今年夏天才破解出来。我们可以将SHA1和RSA或DSA配合在一起使用,目前DSA的密钥位数高达1024位,这个密钥位数已经足够长了,因此不需要担心安全问题。然而,如果NIST实现了更长的密钥位数当然更好。

    X.509证书是一个数据结构,常用于规定比特和字节的顺序,它本身不是一个密码系统。它通常包含一个RSA密钥,也可能包含一个DSA密钥。但是X.509证书内部以及证书本身并不是加密技术。

    转自:https://www.cnblogs.com/lvdongjie/p/4241107.html

    展开全文
  • 对称加密和非对称加密的区别

    万次阅读 多人点赞 2018-08-13 17:53:37
    非对称加密:与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)私有密钥(privatekey)。 对称加密算法: 密钥较短,破译困难,除了数据加密标准(DES),另一个对称密钥加密系统是国际数据...

    简介:

    • 对称加密: 加密和解密的秘钥使用的是同一个.
    • 非对称加密: 与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。

    对称加密算法: 密钥较短,破译困难,除了数据加密标准(DES),另一个对称密钥加密系统是国际数据加密算法(IDEA),它比DES的加密性好,且对计算机性能要求也没有那么高.

    优点:

        算法公开、计算量小、加密速度快、加密效率高

    缺点:

        在数据传送前,发送方和接收方必须商定好秘钥,然后 使双方都能保存好秘钥。其次如果一方的秘钥被泄露,那么加密信息也就不安全了。另外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的唯一秘钥,这会使得收、发双方所拥有的钥匙数量巨大,密钥管理成为双方的负担。

    常见的对称加密算法有: DES、3DES、Blowfish、IDEA、RC4、RC5、RC6 和 AES 

    非对称加密算法: 公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

    非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。甲方只能用其专用密钥解密由其公用密钥加密后的任何信息。

    优点:

        安全

    缺点:

        速度较慢

    常见的非对称加密算法有: RSA、ECC(移动设备用)、Diffie-Hellman、El Gamal、DSA(数字签名用)

    Hash算法(摘要算法)

    Hash算法特别的地方在于它是一种单向算法,用户可以通过hash算法对目标信息生成一段特定长度的唯一hash值,却不能通过这个hash值重新获得目标信息。因此Hash算法常用在不可还原的密码存储、信息完整性校验等。

    常见的摘要算法有: MD2、MD4、MD5、HAVAL、SHA

     

    非常感谢 qq_42281306 https://me.csdn.net/qq_42281306 朋友的指出

    展开全文
  • 关于对称加密和非对称加密关于对称加密和非对称加密目前加密方式主要有两种: 对称加密和非对称加密通信过程(非对称加密关于中间人攻击(非对称加密关于数字签名(非对称加密关于RSA签名(数字签名证书认证机构 CA...
  • 对称加密和非对称加密的比较

    千次阅读 2015-03-16 09:54:49
    对称加密和非对称加密的比较
  • 对称加密和非对称加密总结

    千次阅读 2016-08-04 14:17:19
    对称加密含义:对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密...非对称加密含义:非对称加密为数据的加密与解密提供了一个非常安全的方法,它使用了一对密钥,公钥(public key)私钥(pr
  • 对称加密和非对称加密详解

    千次阅读 2018-09-01 18:33:57
    数据加密算法主要分为两大类:对称加密和非对称加密 下面我们来看一下他们的区别的各自的作用   下面详细介绍两种加密方式的具体过程 (1)交易加密或者区块加密(对称加密) 为了让区块链中的交易信息或者...
  • 对称加密采用了对称密码编码技术,它的特点是文件加密解密使用相同的密钥加密 也就是密钥也可以用作解密密钥,这种方法在密码学中叫做对称加密算法,对称加密算法使用起来简单快捷,密钥较短,且破译困难,除了...
  • 非对称加密是有公钥私钥两个秘钥的. 对称加密速度相对更快,但安全性较低,如果一方的秘钥泄露,那密文就相当于明码了. 而非对称加密速度相对较慢,但安全性更高.(速度我自测过SHA256RSA,签名验签大约0-10ms,性能...
  • 对称加密和非对称加密(一)初步理解

    万次阅读 多人点赞 2018-12-26 23:23:21
    先查大范围 专业术语 再查小范围 便于... 从而出现了:对称加密和非对称加密。 二、对称加密和非对称加密 1. 对称加密 对称加密指的就是加密和解密使用同一个秘钥,所以叫做对称加密对称加密只有一个秘钥,...
  • java对称加密非对称加密

    万次阅读 2017-11-26 22:25:49
    java对称加密与非对称加密加密方式大致分为两种,对称加密和非对称加密对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。非对称加密为数据的加密...
  • 对称加密和非对称加密

    千次阅读 2011-03-03 11:13:00
    主要是对称加密和非对称加密两种。可供各位参考: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography; using System.IO; namespace ...
  • 目录 一、对称加密(Symmetric Cryptography) 优缺点 二、非对称加密(asymmetric Cryptography) ...非对称加密算法使用了一对密钥,公钥与私钥,所以安全性高,但加密与解密速度慢,解决加密解密慢的...
  • 非对称加密算法: 加密解密使用不同的密钥。公钥只能用来加密,而私钥只能用来解密。私钥由用户自己拥有。公钥公开配送,只要有需求即可获得。 优点: 算法安全性高,公钥公开,私钥自己保存 缺点: 加密...
  • 对称加密非对称加密 对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。对称加密有很多种算法,由于它效率很高,所以被广泛使用在很多加密协议的...
  • client请求服务端(指定SSL版本和加密组件) server返回CA证书+公钥 client用机构公钥认证server返回的CA证书上的签名是否正确 client生成一个密钥R,用公钥对密钥R加密发送给server server用服务器的私钥解密...
  • Android开发-对称加密和非对称加密

    千次阅读 2018-07-09 15:26:31
    参考资料: 对称加密和非对称加密 MD5加密算法
  • 对称加密指的就是加密解密使用同一个秘钥,所以叫做对称加密对称加密只有一个秘钥,作为私钥。 具体算法有:DES,3DES,TDEA,Blowfish,RC5,IDEA。常见的有:DES,AES,3DES等等。 优点: 算法公开、计算量...
  • 加密类型:对称加密非对称加密,   对称加密:微信小程序 算法 AES 非对称加密:支付宝 算法RSA &lt;?php /** * Created by PhpStorm. * User: lj * Date: 2018/10/21 * Time: 3:20 PM * ...
  • Android安全-对称加密和非对称加密

    千次阅读 2016-01-07 19:31:44
    秘钥:分为加密秘钥解密秘钥 明文:没有进行加密,能够直接代表原文含义的信息 密文:经过加密处理之后,隐藏原文含义的信息 加密:将明文转换为密文的过程 解密:将密文转换为明文...RSA:非对称加密,有公钥私钥
  • 对称加密算法和非对称加密算法

    千次阅读 2019-03-17 15:59:04
    有一种加密算法叫做对称加密对称加密是以前比较常见的一种加密方式。所谓对称加密的意思是说假如有一个人A,他想把一个信号m传递给B,他不能直接将这个信息传递给B,否则会有人可能会窃听。于是通过一些算法,...
  • 对称加密和非对称加密介绍和区别

    千次阅读 2015-08-31 10:44:45
    对称加密采用了对称密码编码技术,它的特点是文件加密解密使用相同的密钥,即加密密钥也可以用作解密密钥,这种方法在密码学中叫做对称加密算法,对称加密算法使用起来简单快捷,密钥较短,且破译困难,除了数据...
  • 对称加密和非对称加密的详细说明

    千次阅读 2018-12-17 09:55:57
    为了保密,一般在网络上传输的重要数据文件都可以对其进行加密,但数据加密也不一定是为了在网络间传输文件,而是为了保证机密文件即使失窃后也不泄漏其中的重要信息。 数据加密的作用:  ...
  • 对称加密&非对称加密&混合加密

    千次阅读 2018-11-09 10:23:13
    混合加密写于前iOS中常在哪些场景应用到写一个系列本文概要对称加密(Symmetric Cryptography)非对称加密(ASymmetric Cryptography)混合加密(Hybrid Cryptography)总结 写于前 iOS中常在哪些场景应用到 支付密码、...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 100,559
精华内容 40,223
关键字:

对称加密和非对称加密例子