龙空技术网

面试官:你知道微信支付的签名算法吗?讲一讲你所了解的密码学

A秋天的铁工匠 157

前言:

目前朋友们对“微型加密算法”大致比较珍视,朋友们都想要学习一些“微型加密算法”的相关知识。那么小编同时在网络上收集了一些关于“微型加密算法””的相关文章,希望看官们能喜欢,朋友们快快来学习一下吧!

微信下单签名算法支付宝下单签名算法

我们常用的加密算法中BASE64、MD5、RSA、SHA、HMAC等之间的区别

BASE64

按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.) 常见于邮件、http加密,截取http信息,你就会发现登录操作的用户名、密码字段通过BASE64加密的。

/**  * BASE64解密  *   * @param key  * @return  * @throws Exception  */  public static byte[] decryptBASE64(String key) throws Exception {      return (new BASE64Decoder()).decodeBuffer(key);  }    /**  * BASE64加密  *   * @param key  * @return  * @throws Exception  */  public static String encryptBASE64(byte[] key) throws Exception {      return (new BASE64Encoder()).encodeBuffer(key);  }

主要就是BASE64Encoder、BASE64Decoder两个类,我们只需要知道使用对应的方法即可。另,BASE加密后产生的字节位数是8的倍数,如果不够位数以=符号填充

MD5

MD5 -- message-digest algorithm 5 (信息-摘要算法)缩写,广泛用于加密和解密技术,常用于文件校验。校验?不管文件多大,经过MD5后都能生成唯一的MD5值。好比现在的ISO校验,都是MD5校验。怎么用?当然是把ISO经过MD5后产生MD5的值。一般下载linux-ISO的朋友都见过下载链接旁边放着MD5的串。就是用来验证文件是否一致的。

/**  * MD5加密  *   * @param data  * @return  * @throws Exception  */  public static byte[] encryptMD5(byte[] data) throws Exception {        MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);      md5.update(data);        return md5.digest();    }

RSA

RSA公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,由于无法计算出大数n的欧拉函数phi(N),所以不能根据PK计算出SK。

package com.chen.test;import org.apache.commons.codec.binary.Base64;import org.apache.commons.io.IOUtils;import javax.crypto.Cipher;import java.io.ByteArrayOutputStream;import java.security.*;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.HashMap;import java.util.Map;public class RSAUtils {    public static final String CHARSET = "UTF-8";    public static final String RSA_ALGORITHM = "RSA";    public static Map<String, String> createKeys(int keySize){        //为RSA算法创建一个KeyPairGenerator对象        KeyPairGenerator kpg;        try{            kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);        }catch(NoSuchAlgorithmException e){            throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");        }        //初始化KeyPairGenerator对象,密钥长度        kpg.initialize(keySize);        //生成密匙对        KeyPair keyPair = kpg.generateKeyPair();        //得到公钥        Key publicKey = keyPair.getPublic();        String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());        //得到私钥        Key privateKey = keyPair.getPrivate();        String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());        Map<String, String> keyPairMap = new HashMap<String, String>();        keyPairMap.put("publicKey", publicKeyStr);        keyPairMap.put("privateKey", privateKeyStr);        return keyPairMap;    }    /**     * 得到公钥     * @param publicKey 密钥字符串(经过base64编码)     * @throws Exception     */    public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {        //通过X509编码的Key指令获得公钥对象        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));        RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);        return key;    }    /**     * 得到私钥     * @param privateKey 密钥字符串(经过base64编码)     * @throws Exception     */    public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {        //通过PKCS#8编码的Key指令获得私钥对象        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));        RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);        return key;    }    /**     * 公钥加密     * @param data     * @param publicKey     * @return     */    public static String publicEncrypt(String data, RSAPublicKey publicKey){        try{            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);            cipher.init(Cipher.ENCRYPT_MODE, publicKey);            return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength()));        }catch(Exception e){            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);        }    }    /**     * 私钥解密     * @param data     * @param privateKey     * @return     */    public static String privateDecrypt(String data, RSAPrivateKey privateKey){        try{            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);            cipher.init(Cipher.DECRYPT_MODE, privateKey);            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), CHARSET);        }catch(Exception e){            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);        }    }    /**     * 私钥加密     * @param data     * @param privateKey     * @return     */    public static String privateEncrypt(String data, RSAPrivateKey privateKey){        try{            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);            cipher.init(Cipher.ENCRYPT_MODE, privateKey);            return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength()));        }catch(Exception e){            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);        }    }    /**     * 公钥解密     * @param data     * @param publicKey     * @return     */    public static String publicDecrypt(String data, RSAPublicKey publicKey){        try{            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);            cipher.init(Cipher.DECRYPT_MODE, publicKey);            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), CHARSET);        }catch(Exception e){            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);        }    }    private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize){        int maxBlock = 0;        if(opmode == Cipher.DECRYPT_MODE){            maxBlock = keySize / 8;        }else{            maxBlock = keySize / 8 - 11;        }        ByteArrayOutputStream out = new ByteArrayOutputStream();        int offSet = 0;        byte[] buff;        int i = 0;        try{            while(datas.length > offSet){                if(datas.length-offSet > maxBlock){                    buff = cipher.doFinal(datas, offSet, maxBlock);                }else{                    buff = cipher.doFinal(datas, offSet, datas.length-offSet);                }                out.write(buff, 0, buff.length);                i++;                offSet = i * maxBlock;            }        }catch(Exception e){            throw new RuntimeException("加解密阀值为["+maxBlock+"]的数据时发生异常", e);        }        byte[] resultDatas = out.toByteArray();        IOUtils.closeQuietly(out);        return resultDatas;    }}
SHASHA(Secure Hash Algorithm,安全散列算法),数字签名等密码学应用中重要的工具,被广泛地应用于电子商务等信息安全领域。虽然,SHA与MD5通过碰撞法都被破解了, 但是SHA仍然是公认的安全加密算法,较之MD5更为安全。
/**      * SHA加密      *       * @param data      * @return      * @throws Exception      */      public static byte[] encryptSHA(byte[] data) throws Exception {            MessageDigest sha = MessageDigest.getInstance(KEY_SHA);          sha.update(data);            return sha.digest();        }  }
HMAC

HMAC(Hash Message Authentication Code,散列消息鉴别码,基于密钥的Hash算法的认证协议。消息鉴别码实现鉴别的原理是,用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。

/**  * 初始化HMAC密钥  *   * @return  * @throws Exception  */  public static String initMacKey() throws Exception {      KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);        SecretKey secretKey = keyGenerator.generateKey();      return encryptBASE64(secretKey.getEncoded());  }    /**  * HMAC加密  *   * @param data  * @param key  * @return  * @throws Exception  */  public static byte[] encryptHMAC(byte[] data, String key) throws Exception {        SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC);      Mac mac = Mac.getInstance(secretKey.getAlgorithm());      mac.init(secretKey);        return mac.doFinal(data);    } 
完整类(不包含RSA加密算法)

mport java.security.MessageDigest;    import javax.crypto.KeyGenerator;  import javax.crypto.Mac;  import javax.crypto.SecretKey;    import sun.misc.BASE64Decoder;  import sun.misc.BASE64Encoder;    /**  * 基础加密组件  *   * @author 梁栋  * @version 1.0  * @since 1.0  */  public abstract class Coder {      public static final String KEY_SHA = "SHA";      public static final String KEY_MD5 = "MD5";        /**      * MAC算法可选以下多种算法      *       * <pre>      * HmacMD5       * HmacSHA1       * HmacSHA256       * HmacSHA384       * HmacSHA512      * </pre>      */      public static final String KEY_MAC = "HmacMD5";        /**      * BASE64解密      *       * @param key      * @return      * @throws Exception      */      public static byte[] decryptBASE64(String key) throws Exception {          return (new BASE64Decoder()).decodeBuffer(key);      }        /**      * BASE64加密      *       * @param key      * @return      * @throws Exception      */      public static String encryptBASE64(byte[] key) throws Exception {          return (new BASE64Encoder()).encodeBuffer(key);      }        /**      * MD5加密      *       * @param data      * @return      * @throws Exception      */      public static byte[] encryptMD5(byte[] data) throws Exception {            MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);          md5.update(data);            return md5.digest();        }        /**      * SHA加密      *       * @param data      * @return      * @throws Exception      */      public static byte[] encryptSHA(byte[] data) throws Exception {            MessageDigest sha = MessageDigest.getInstance(KEY_SHA);          sha.update(data);            return sha.digest();        }        /**      * 初始化HMAC密钥      *       * @return      * @throws Exception      */      public static String initMacKey() throws Exception {          KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);            SecretKey secretKey = keyGenerator.generateKey();          return encryptBASE64(secretKey.getEncoded());      }        /**      * HMAC加密      *       * @param data      * @param key      * @return      * @throws Exception      */      public static byte[] encryptHMAC(byte[] data, String key) throws Exception {            SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC);          Mac mac = Mac.getInstance(secretKey.getAlgorithm());          mac.init(secretKey);            return mac.doFinal(data);        }  }
测试类
import static org.junit.Assert.*;    import org.junit.Test;    /**  *   * @author 梁栋  * @version 1.0  * @since 1.0  */  public class CoderTest {        @Test      public void test() throws Exception {          String inputStr = "简单加密";          System.err.println("原文:/n" + inputStr);            byte[] inputData = inputStr.getBytes();          String code = Coder.encryptBASE64(inputData);            System.err.println("BASE64加密后:/n" + code);            byte[] output = Coder.decryptBASE64(code);            String outputStr = new String(output);            System.err.println("BASE64解密后:/n" + outputStr);            // 验证BASE64加密解密一致性          assertEquals(inputStr, outputStr);            // 验证MD5对于同一内容加密是否一致          assertArrayEquals(Coder.encryptMD5(inputData), Coder                  .encryptMD5(inputData));            // 验证SHA对于同一内容加密是否一致          assertArrayEquals(Coder.encryptSHA(inputData), Coder                  .encryptSHA(inputData));            String key = Coder.initMacKey();          System.err.println("Mac密钥:/n" + key);            // 验证HMAC对于同一内容,同一密钥加密是否一致          assertArrayEquals(Coder.encryptHMAC(inputData, key), Coder.encryptHMAC(                  inputData, key));            BigInteger md5 = new BigInteger(Coder.encryptMD5(inputData));          System.err.println("MD5:/n" + md5.toString(16));            BigInteger sha = new BigInteger(Coder.encryptSHA(inputData));          System.err.println("SHA:/n" + sha.toString(32));            BigInteger mac = new BigInteger(Coder.encryptHMAC(inputData, inputStr));          System.err.println("HMAC:/n" + mac.toString(16));      }  }
结果

原文:  简单加密  BASE64加密后:  566A5Y2V5Yqg5a+G    BASE64解密后:  简单加密  Mac密钥:  uGxdHC+6ylRDaik++leFtGwiMbuYUJ6mqHWyhSgF4trVkVBBSQvY/a22xU8XT1RUemdCWW155Bke  pBIpkd7QHg==    MD5:  -550b4d90349ad4629462113e7934de56  SHA:  91k9vo7p400cjkgfhjh0ia9qthsjagfn  HMAC:  2287d192387e95694bdbba2fa941009a

标签: #微型加密算法 #hash算法数字签名实例 #微信signature算法