java(计算机)常见加密算法详解

摘要:
BASE64编码算法不是真正的加密算法。MD5、SHA和HMAC是不可逆加密,这是一种无法解密的加密方法。我们称之为单向加密算法。MD5MD5的缩写--消息摘要算法5,广泛用于加密和解密技术以及文件验证。通常,MD5生成的字节数组被提供给BASE64进行加密,以获得相应的字符串。尽管SHA和MD5已经被冲突破解,但SHA仍然是公认的安全加密算法,比MD5.HMACHMMAC(HashMessage Authentication Code,哈希消息认证码,以及基于密钥的哈希算法认证协议)更安全。

  来源:http://blog.csdn.net/janronehoo/article/category/1152295

 如基本的单向加密算法:

  • BASE64 严格地说,属于编码格式,而非加密算法
  • MD5(Message Digest algorithm 5,信息摘要算法)
  • SHA(Secure Hash Algorithm,安全散列算法)
  • HMAC(Hash Message Authentication Code,散列消息鉴别码)


    复杂的对称加密(DES、PBE)、非对称加密算法:

    • DES(Data Encryption Standard,数据加密算法)
    • PBE(Password-based encryption,基于密码验证)
    • RSA(算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman)
    • DH(Diffie-Hellman算法,密钥一致协议)
    • DSA(Digital Signature Algorithm,数字签名)
    • ECC(Elliptic Curves Cryptography,椭圆曲线密码编码学)


-------------------------------------------------------------------------------------------------------------------------------------------

本篇内容简要介绍BASE64、MD5、SHA、HMAC几种加密算法。
BASE64编码算法不算是真正的加密算法。
MD5、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加密的。

                       

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

sun不推荐使用它们自己的base64,所以用apache的挺好!


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



通常我们不直接使用上述MD5加密。通常将MD5产生的字节数组交给BASE64再加密一把,得到相应的字符串。


SHA
SHA(Secure Hash Algorithm,安全散列算法),数字签名等密码学应用中重要的工具,被广泛地应用于电子商务等信息安全领域。虽然,SHA与MD5通过碰撞法都被破解了,但是SHA仍然是公认的安全加密算法,较之MD5更为安全。



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



BASE64的加密解密是双向的,可以求反解。
MD5、SHA以及HMAC是单向加密,任何数据加密后只会产生唯一的一个加密串,通常用来校验数据在传输过程中是否被修改。其中HMAC算法有一个密钥,增强了数据传输过程中的安全性,强化了算法外的不可控因素。[img]http://www.iteye.com/images/smiles/icon_biggrin.gif" alt="[/img]
单向加密的用途主要是为了校验数据在传输过程中是否被修改。


代码如下:

Java代码

  1. import      java.math.BigInteger;
  2. import java.security.InvalidKeyException;     
  3. import      java.security.MessageDigest;
  4. import      java.security.NoSuchAlgorithmException;
  5. import      javax.crypto.KeyGenerator;
  6. import      javax.crypto.Mac;
  7. import      javax.crypto.SecretKey;
  8. import      javax.crypto.spec.SecretKeySpec;
  9. import      org.apache.commons.codec.binary.Base64;
  10.  
  11. public class      MyEncrypt {
  12. public static      final String KEY_SHA = "SHA";
  13. public static      final String KEY_MD5 = "MD5";
  14. public static      final String KEY_MAC = "HmacMD5";
  15.  
  16.  
  17. // sun不推荐使用它们自己的base64,用apache的挺好     
  18. /**
  19. * BASE64解密
  20. */
  21. public static      byte[] decryptBASE64(byte[] dest) {
  22. if (dest == null)      {
  23. return null;
  24. }
  25. return      Base64.decodeBase64(dest);
  26. }
  27.  
  28. /**
  29. * BASE64加密
  30. */
  31. public static      byte[] encryptBASE64(byte[] origin) {
  32. if (origin ==      null) {
  33. return null;
  34. }
  35. return      Base64.encodeBase64(origin);
  36. }
  37.  
  38. /**
  39. * MD5加密
  40. *
  41. * @throws      NoSuchAlgorithmException
  42. */
  43. public static      byte[] encryptMD5(byte[] data)
  44. throws      NoSuchAlgorithmException {
  45. if (data == null)      {
  46. return null;
  47. }
  48. MessageDigest      md5 = MessageDigest.getInstance(KEY_MD5);
  49. md5.update(data);     
  50. return      md5.digest();
  51. }
  52.  
  53. /**
  54. * SHA加密
  55. *
  56. * @throws      NoSuchAlgorithmException
  57. */
  58. public static      byte[] encryptSHA(byte[] data)
  59. throws      NoSuchAlgorithmException {
  60. if (data == null)      {
  61. return null;
  62. }
  63. MessageDigest      sha = MessageDigest.getInstance(KEY_SHA);
  64. sha.update(data);     
  65. return      sha.digest();
  66. }
  67.  
  68. /**
  69. * 初始化HMAC密钥
  70. *
  71. * @throws      NoSuchAlgorithmException
  72. */
  73. public static      String initMacKey() throws NoSuchAlgorithmException {
  74. KeyGenerator      keyGenerator = KeyGenerator.getInstance(KEY_MAC);
  75. SecretKey      secretKey = keyGenerator.generateKey();
  76. return new      String(encryptBASE64(secretKey.getEncoded()));
  77. }
  78.  
  79. /**
  80. * HMAC加密
  81. *
  82. * @throws      NoSuchAlgorithmException
  83. * @throws      InvalidKeyException
  84. */
  85. public static      byte[] encryptHMAC(byte[] data, String key)
  86. throws      NoSuchAlgorithmException, InvalidKeyException {
  87. SecretKey      secretKey = new SecretKeySpec(decryptBASE64(key.getBytes()),
  88. KEY_MAC);
  89. Mac mac =      Mac.getInstance(secretKey.getAlgorithm());
  90. mac.init(secretKey);     
  91. return      mac.doFinal(data);
  92.  
  93. }
  94.  
  95. public static      void main(String[] args) throws Exception {
  96. // TODO      Auto-generated method stub
  97. String data =      "简单加密";
  98. System.out.println(new      BigInteger(encryptBASE64(data.getBytes())).toString(16));
  99. System.out.println(new      BigInteger(encryptBASE64(data.getBytes())).toString(32));
  100. System.out.println(new      String(decryptBASE64(encryptBASE64(data.getBytes()))));
  101.  
  102. System.out.println(new      BigInteger(encryptMD5(data.getBytes())).toString());
  103. System.out.println(new      BigInteger(encryptSHA(data.getBytes())).toString());
  104.  
  105. System.out.println(new      BigInteger(encryptHMAC(data.getBytes(), initMacKey())).toString());
  106. }
  107.  
  108. }

import java.math.BigInteger;

import java.security.InvalidKeyException;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

import javax.crypto.KeyGenerator;

import javax.crypto.Mac;

import javax.crypto.SecretKey;

import javax.crypto.spec.SecretKeySpec;

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

 

public class MyEncrypt {

public static final String KEY_SHA = "SHA";

public static final String KEY_MD5 = "MD5";

public static final String KEY_MAC = "HmacMD5";

 

 

// sun不推荐使用它们自己的base64,用apache的挺好

/**

* BASE64解密

*/

public static byte[] decryptBASE64(byte[] dest) {

if (dest == null) {

return null;

}

return Base64.decodeBase64(dest);

}

 

/**

* BASE64加密

*/

public static byte[] encryptBASE64(byte[] origin) {

if (origin == null) {

return null;

}

return Base64.encodeBase64(origin);

}

 

/**

* MD5加密

*

* @throws NoSuchAlgorithmException

*/

public static byte[] encryptMD5(byte[] data)

throws NoSuchAlgorithmException {

if (data == null) {

return null;

}

MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);

md5.update(data);

return md5.digest();

}

 

/**

* SHA加密

*

* @throws NoSuchAlgorithmException

*/

public static byte[] encryptSHA(byte[] data)

throws NoSuchAlgorithmException {

if (data == null) {

return null;

}

MessageDigest sha = MessageDigest.getInstance(KEY_SHA);

sha.update(data);

return sha.digest();

}

 

/**

* 初始化HMAC密钥

*

* @throws NoSuchAlgorithmException

*/

public static String initMacKey() throws NoSuchAlgorithmException {

KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);

SecretKey secretKey = keyGenerator.generateKey();

return new String(encryptBASE64(secretKey.getEncoded()));

}

 

/**

* HMAC加密

*

* @throws NoSuchAlgorithmException

* @throws InvalidKeyException

*/

public static byte[] encryptHMAC(byte[] data, String key)

throws NoSuchAlgorithmException, InvalidKeyException {

SecretKey secretKey = new SecretKeySpec(decryptBASE64(key.getBytes()),

KEY_MAC);

Mac mac = Mac.getInstance(secretKey.getAlgorithm());

mac.init(secretKey);

return mac.doFinal(data);

 

}

 

public static void main(String[] args) throws Exception {

// TODO Auto-generated method stub

String data = "简单加密";

System.out.println(new BigInteger(encryptBASE64(data.getBytes())).toString(16));

System.out.println(new BigInteger(encryptBASE64(data.getBytes())).toString(32));

System.out.println(new String(decryptBASE64(encryptBASE64(data.getBytes()))));

 

System.out.println(new BigInteger(encryptMD5(data.getBytes())).toString());

System.out.println(new BigInteger(encryptSHA(data.getBytes())).toString());

 

System.out.println(new BigInteger(encryptHMAC(data.getBytes(), initMacKey())).toString());

}

 

}



------------------------------------------------------------------------------------------------------------------------------------------------------------

可变MD5加密(Java实现)

可变在这里含义很简单,就是最终的加密结果是可变的,而非必需按标准MD5加密实现。Java类库security中的MessageDigest类就提供了MD5加密的支持,实现起来非常方便。为了实现更多效果,我们可以如下设计MD5工具类。

Java代码

  1. import      java.security.MessageDigest;
  2.  
  3. /**
  4. * 标准MD5加密方法,使用java类库的security包的MessageDigest类处理
  5. */
  6. public class MD5      {
  7. /**
  8. * 获得MD5加密密码的方法
  9. */
  10. public static      String getMD5ofStr(String origString) {
  11. String      origMD5 = null;
  12. try {
  13. MessageDigest      md5 = MessageDigest.getInstance("MD5");
  14. //      md5.update(origString.getBytes());
  15. byte[] result      = md5.digest(origString.getBytes());
  16. origMD5 =      byteArray2HexStr(result);
  17. // if      ("123".equals(origString)) {
  18. //      System.out.println(new String(result));
  19. //      System.out.println(new BigInteger(result).toString(16));
  20. // }
  21. } catch      (Exception e) {
  22. e.printStackTrace();     
  23. }
  24. return      origMD5;
  25. }
  26.  
  27. /**
  28. * 处理字节数组得到MD5密码的方法
  29. */
  30. private static      String byteArray2HexStr(byte[] bs) {
  31. StringBuffer      sb = new StringBuffer();
  32. for (byte b :      bs) {
  33. sb.append(byte2HexStr(b));     
  34. }
  35. return      sb.toString();
  36. }
  37.  
  38. /**
  39. * 字节标准移位转十六进制方法
  40. */
  41. private static      String byte2HexStr(byte b) {
  42. String hexStr      = null;
  43. int n = b;
  44. if (n < 0)      {
  45. // 若需要自定义加密,请修改这个移位算法即可
  46. n = b & 0x7F      + 128;
  47. }
  48. hexStr =      Integer.toHexString(n / 16) + Integer.toHexString(n % 16);
  49. return      hexStr.toUpperCase();
  50. }
  51.  
  52. /**
  53. * 提供一个MD5多次加密方法
  54. */
  55. public static      String getMD5ofStr(String origString, int times) {
  56. String md5 =      getMD5ofStr(origString);
  57. for (int i = 0;      i < times - 1; i++) {
  58. md5 =      getMD5ofStr(md5);
  59. }
  60. return      getMD5ofStr(md5);
  61. }
  62.  
  63. /**
  64. * 密码验证方法
  65. */
  66. public static      boolean verifyPassword(String inputStr, String MD5Code) {
  67. return      getMD5ofStr(inputStr).equals(MD5Code);
  68. }
  69.  
  70. /**
  71. * 重载一个多次加密时的密码验证方法
  72. */
  73. public static      boolean verifyPassword(String inputStr, String MD5Code,
  74. int times) {
  75. return      getMD5ofStr(inputStr, times).equals(MD5Code);
  76. }
  77.  
  78. /**
  79. * 提供一个测试的主函数
  80. */
  81. public static      void main(String[] args) {
  82. System.out.println("123:"      + getMD5ofStr("123"));
  83. System.out.println("123456789:"      + getMD5ofStr("123456789"));
  84. System.out.println("sarin:"      + getMD5ofStr("sarin"));
  85. System.out.println("123:"      + getMD5ofStr("123", 4));
  86. }
  87. }

import java.security.MessageDigest;

 

/**

 * 标准MD5加密方法,使用java类库的security包的MessageDigest类处理

 */

public class MD5 {

  /**

   * 获得MD5加密密码的方法

   */

  public static String getMD5ofStr(String origString) {

    String origMD5 = null;

    try {

      MessageDigest md5 = MessageDigest.getInstance("MD5");

      // md5.update(origString.getBytes());

      byte[] result = md5.digest(origString.getBytes());

      origMD5 = byteArray2HexStr(result);

      // if ("123".equals(origString)) {

      // System.out.println(new String(result));

      // System.out.println(new BigInteger(result).toString(16));

      // }

    } catch (Exception e) {

      e.printStackTrace();

    }

    return origMD5;

  }

 

  /**

   * 处理字节数组得到MD5密码的方法

   */

  private static String byteArray2HexStr(byte[] bs) {

    StringBuffer sb = new StringBuffer();

    for (byte b : bs) {

      sb.append(byte2HexStr(b));

    }

    return sb.toString();

  }

 

  /**

   * 字节标准移位转十六进制方法

   */

  private static String byte2HexStr(byte b) {

    String hexStr = null;

    int n = b;

    if (n < 0) {

      // 若需要自定义加密,请修改这个移位算法即可

      n = b & 0x7F + 128;

    }

    hexStr = Integer.toHexString(n / 16) + Integer.toHexString(n % 16);

    return hexStr.toUpperCase();

  }

 

  /**

   * 提供一个MD5多次加密方法

   */

  public static String getMD5ofStr(String origString, int times) {

    String md5 = getMD5ofStr(origString);

    for (int i = 0; i < times - 1; i++) {

      md5 = getMD5ofStr(md5);

    }

    return getMD5ofStr(md5);

  }

 

  /**

   * 密码验证方法

   */

  public static boolean verifyPassword(String inputStr, String MD5Code) {

    return getMD5ofStr(inputStr).equals(MD5Code);

  }

 

  /**

   * 重载一个多次加密时的密码验证方法

   */

  public static boolean verifyPassword(String inputStr, String MD5Code,

      int times) {

    return getMD5ofStr(inputStr, times).equals(MD5Code);

  }

 

  /**

   * 提供一个测试的主函数

   */

  public static void main(String[] args) {

    System.out.println("123:" + getMD5ofStr("123"));

    System.out.println("123456789:" + getMD5ofStr("123456789"));

    System.out.println("sarin:" + getMD5ofStr("sarin"));

    System.out.println("123:" + getMD5ofStr("123", 4));

  }

}

可以看出实现的过程非常简单,因为由java类库提供了处理支持。但是要清楚的是这种方式产生的密码不是标准的MD5码,它需要进行移位处理才能得到标准MD5码。这个程序的关键之处也在这了,怎么可变?调整移位算法不就可变了么!不进行移位,也能够得到32位的密码,这就不是标准加密了,只要加密和验证过程使用相同的算法就可以了。
MD5加密还是很安全的,像CMD5那些穷举破解的只是针对标准MD5加密的结果进行的,如果自定义移位算法后,它还有效么?可以说是无解的了,所以MD5非常安全可靠。
为了更可变,还提供了多次加密的方法,可以在MD5基础之上继续MD5,就是对32位的第一次加密结果再MD5,恩,这样去破解?没有任何意义。
这样在MIS系统中使用,安全可靠,欢迎交流,希望对使用者有用。
我们最后看看由MD5加密算法实现的类,那是非常庞大的。

Java代码

  1. import      java.lang.reflect.*;
  2.  
  3. /**
  4. * **********************************************     
  5. * md5 类实现了RSA Data Security, Inc.在提交给IETF
  6. * 的RFC1321中的MD5 message-digest      算法。
  7. *      ***********************************************
  8. */
  9.  
  10. public class      MD5 {
  11. /* 下面这些S11-S44实际上是一个4*4的矩阵,在原始的C实现中是用#define 实现的,
  12. 这里把它们实现成为static      final是表示了只读,切能在同一个进程空间内的多个
  13. Instance间共享*/
  14. static final int      S11 = 7;
  15. static final int      S12 = 12;
  16. static final int      S13 = 17;
  17. static final int      S14 = 22;
  18.  
  19. static final int      S21 = 5;
  20. static final int      S22 = 9;
  21. static final int      S23 = 14;
  22. static final int      S24 = 20;
  23.  
  24. static final int      S31 = 4;
  25. static final int      S32 = 11;
  26. static final int      S33 = 16;
  27. static final int      S34 = 23;
  28.  
  29. static final int      S41 = 6;
  30. static final int      S42 = 10;
  31. static final int      S43 = 15;
  32. static final int      S44 = 21;
  33.  
  34. static final byte[]      PADDING = { -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,      0, 0, 0, 0, 0, 0, 0,
  35. 0, 0, 0, 0, 0,      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,      0, 0, 0, 0, 0, 0,
  36. 0 };
  37. /* 下面的三个成员是MD5计算过程中用到的3个核心数据,在原始的C实现中
  38. 被定义到MD5_CTX结构中     
  39.  
  40. */
  41. private long[]      state = new long[4]; // state (ABCD)
  42. private long[]      count = new long[2]; // number of bits, modulo 2^64 (lsb first)
  43. private byte[]      buffer = new byte[64]; // input buffer
  44.  
  45. /* digestHexStr是MD5的唯一一个公共成员,是最新一次计算结果的
  46.   16进制ASCII表示.
  47. */
  48. public String      digestHexStr;
  49.  
  50. /* digest,是最新一次计算结果的2进制内部表示,表示128bit的MD5值.
  51. */
  52. private byte[]      digest = new byte[16];
  53.  
  54. /*
  55. getMD5ofStr是类MD5最主要的公共方法,入口参数是你想要进行MD5变换的字符串     
  56. 返回的是变换完的结果,这个结果是从公共成员digestHexStr取得的.
  57. */
  58. public String      getMD5ofStr(String inbuf) {
  59. md5Init();
  60. md5Update(inbuf.getBytes(),      inbuf.length());
  61. md5Final();
  62. digestHexStr      = "";
  63. for (int i = 0;      i < 16; i++) {
  64. digestHexStr      += byteHEX(digest[i]);
  65. }
  66. return digestHexStr;     
  67.  
  68. }
  69.  
  70. // 这是MD5这个类的标准构造函数,JavaBean要求有一个public的并且没有参数的构造函数
  71. public MD5()      {
  72. md5Init();
  73.  
  74. return;
  75. }
  76.  
  77. /* md5Init是一个初始化函数,初始化核心变量,装入标准的幻数 */
  78. private void      md5Init() {
  79. count[0] =      0L;
  80. count[1] =      0L;
  81. ///* Load      magic initialization constants.
  82.  
  83. state[0] =      0x67452301L;
  84. state[1] =      0xefcdab89L;
  85. state[2] =      0x98badcfeL;
  86. state[3] =      0x10325476L;
  87.  
  88. return;
  89. }
  90.  
  91. /* F, G, H ,I      是4个基本的MD5函数,在原始的MD5的C实现中,由于它们是
  92. 简单的位运算,可能出于效率的考虑把它们实现成了宏,在java中,我们把它们
  93. 实现成了private方法,名字保持了原来C中的。 */
  94.  
  95. private long      F(long x, long y, long z) {
  96. return (x      & y) | ((~x) & z);
  97.  
  98. }
  99.  
  100. private long      G(long x, long y, long z) {
  101. return (x      & z) | (y & (~z));
  102.  
  103. }
  104.  
  105. private long      H(long x, long y, long z) {
  106. return x ^ y      ^ z;
  107. }
  108.  
  109. private long      I(long x, long y, long z) {
  110. return y ^ (x      | (~z));
  111. }
  112.  
  113. /*
  114. FF,GG,HH和II将调用F,G,H,I进行近一步变换
  115. FF, GG, HH,      and II transformations for rounds 1, 2, 3, and 4.
  116. Rotation is      separate from addition to prevent recomputation.
  117. */
  118.  
  119. private long      FF(long a, long b, long c, long d, long x, long s, long ac) {
  120. a += F(b, c,      d) + x + ac;
  121. a = ((int) a      << s) | ((int) a >>> (32 - s));
  122. a += b;
  123. return a;
  124. }
  125.  
  126. private long      GG(long a, long b, long c, long d, long x, long s, long ac) {
  127. a += G(b, c,      d) + x + ac;
  128. a = ((int) a      << s) | ((int) a >>> (32 - s));
  129. a += b;
  130. return a;
  131. }
  132.  
  133. private long      HH(long a, long b, long c, long d, long x, long s, long ac) {
  134. a += H(b, c,      d) + x + ac;
  135. a = ((int) a      << s) | ((int) a >>> (32 - s));
  136. a += b;
  137. return a;
  138. }
  139.  
  140. private long      II(long a, long b, long c, long d, long x, long s, long ac) {
  141. a += I(b, c,      d) + x + ac;
  142. a = ((int) a      << s) | ((int) a >>> (32 - s));
  143. a += b;
  144. return a;
  145. }
  146.  
  147. /*
  148. md5Update是MD5的主计算过程,inbuf是要变换的字节串,inputlen是长度,这个
  149. 函数由getMD5ofStr调用,调用之前需要调用md5init,因此把它设计成private的
  150. */
  151. private void      md5Update(byte[] inbuf, int inputLen) {
  152.  
  153. int i, index,      partLen;
  154. byte[] block      = new byte[64];
  155. index = (int)      (count[0] >>> 3) & 0x3F;
  156. // /* Update      number of bits */
  157. if ((count[0]      += (inputLen << 3)) < (inputLen << 3))
  158. count[1]++;
  159. count[1] +=      (inputLen >>> 29);
  160.  
  161. partLen = 64      - index;
  162.  
  163. // Transform      as many times as possible.
  164. if (inputLen      >= partLen) {
  165. md5Memcpy(buffer,      inbuf, index, 0, partLen);
  166. md5Transform(buffer);     
  167.  
  168. for (i =      partLen; i + 63 < inputLen; i += 64) {
  169.  
  170. md5Memcpy(block,      inbuf, 0, i, 64);
  171. md5Transform(block);     
  172. }
  173. index = 0;
  174.  
  175. } else
  176.  
  177. i = 0;
  178.  
  179. ///* Buffer      remaining input */
  180. md5Memcpy(buffer,      inbuf, index, i, inputLen - i);
  181.  
  182. }
  183.  
  184. /*
  185. md5Final整理和填写输出结果
  186. */
  187. private void      md5Final() {
  188. byte[] bits =      new byte[8];
  189. int index,      padLen;
  190.  
  191. ///* Save      number of bits */
  192. Encode(bits,      count, 8);
  193.  
  194. ///* Pad out      to 56 mod 64.
  195. index = (int)      (count[0] >>> 3) & 0x3f;
  196. padLen =      (index < 56) ? (56 - index) : (120 - index);
  197. md5Update(PADDING,      padLen);
  198.  
  199. ///* Append      length (before padding) */
  200. md5Update(bits,      8);
  201.  
  202. ///* Store      state in digest */
  203. Encode(digest,      state, 16);
  204.  
  205. }
  206.  
  207. /* md5Memcpy是一个内部使用的byte数组的块拷贝函数,从input的inpos开始把len长度的
  208.   字节拷贝到output的outpos位置开始
  209. */
  210.  
  211. private void      md5Memcpy(byte[] output, byte[] input, int outpos, int inpos, int len) {
  212. int i;
  213.  
  214. for (i = 0; i      < len; i++)
  215. output[outpos      + i] = input[inpos + i];
  216. }
  217.  
  218. /*
  219. md5Transform是MD5核心变换程序,有md5Update调用,block是分块的原始字节
  220. */
  221. private void      md5Transform(byte block[]) {
  222. long a =      state[0], b = state[1], c = state[2], d = state[3];
  223. long[] x = new      long[16];
  224.  
  225. Decode(x,      block, 64);
  226.  
  227. /* Round 1 */     
  228. a = FF(a, b,      c, d, x[0], S11, 0xd76aa478L); /* 1 */
  229. d = FF(d, a,      b, c, x[1], S12, 0xe8c7b756L); /* 2 */
  230. c = FF(c, d,      a, b, x[2], S13, 0x242070dbL); /* 3 */
  231. b = FF(b, c,      d, a, x[3], S14, 0xc1bdceeeL); /* 4 */
  232. a = FF(a, b,      c, d, x[4], S11, 0xf57c0fafL); /* 5 */
  233. d = FF(d, a,      b, c, x[5], S12, 0x4787c62aL); /* 6 */
  234. c = FF(c, d,      a, b, x[6], S13, 0xa8304613L); /* 7 */
  235. b = FF(b, c,      d, a, x[7], S14, 0xfd469501L); /* 8 */
  236. a = FF(a, b,      c, d, x[8], S11, 0x698098d8L); /* 9 */
  237. d = FF(d, a, b,      c, x[9], S12, 0x8b44f7afL); /* 10 */
  238. c = FF(c, d,      a, b, x[10], S13, 0xffff5bb1L); /* 11 */
  239. b = FF(b, c,      d, a, x[11], S14, 0x895cd7beL); /* 12 */
  240. a = FF(a, b,      c, d, x[12], S11, 0x6b901122L); /* 13 */
  241. d = FF(d, a,      b, c, x[13], S12, 0xfd987193L); /* 14 */
  242. c = FF(c, d,      a, b, x[14], S13, 0xa679438eL); /* 15 */
  243. b = FF(b, c,      d, a, x[15], S14, 0x49b40821L); /* 16 */
  244.  
  245. /* Round 2 */     
  246. a = GG(a, b,      c, d, x[1], S21, 0xf61e2562L); /* 17 */
  247. d = GG(d, a,      b, c, x[6], S22, 0xc040b340L); /* 18 */
  248. c = GG(c, d,      a, b, x[11], S23, 0x265e5a51L); /* 19 */
  249. b = GG(b, c,      d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */
  250. a = GG(a, b,      c, d, x[5], S21, 0xd62f105dL); /* 21 */
  251. d = GG(d, a,      b, c, x[10], S22, 0x2441453L); /* 22 */
  252. c = GG(c, d,      a, b, x[15], S23, 0xd8a1e681L); /* 23 */
  253. b = GG(b, c,      d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */
  254. a = GG(a, b,      c, d, x[9], S21, 0x21e1cde6L); /* 25 */
  255. d = GG(d, a,      b, c, x[14], S22, 0xc33707d6L); /* 26 */
  256. c = GG(c, d,      a, b, x[3], S23, 0xf4d50d87L); /* 27 */
  257. b = GG(b, c,      d, a, x[8], S24, 0x455a14edL); /* 28 */
  258. a = GG(a, b,      c, d, x[13], S21, 0xa9e3e905L); /* 29 */
  259. d = GG(d, a,      b, c, x[2], S22, 0xfcefa3f8L); /* 30 */
  260. c = GG(c, d,      a, b, x[7], S23, 0x676f02d9L); /* 31 */
  261. b = GG(b, c,      d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */
  262.  
  263. /* Round 3 */     
  264. a = HH(a, b,      c, d, x[5], S31, 0xfffa3942L); /* 33 */
  265. d = HH(d, a,      b, c, x[8], S32, 0x8771f681L); /* 34 */
  266. c = HH(c, d,      a, b, x[11], S33, 0x6d9d6122L); /* 35 */
  267. b = HH(b, c,      d, a, x[14], S34, 0xfde5380cL); /* 36 */
  268. a = HH(a, b, c,      d, x[1], S31, 0xa4beea44L); /* 37 */
  269. d = HH(d, a,      b, c, x[4], S32, 0x4bdecfa9L); /* 38 */
  270. c = HH(c, d,      a, b, x[7], S33, 0xf6bb4b60L); /* 39 */
  271. b = HH(b, c,      d, a, x[10], S34, 0xbebfbc70L); /* 40 */
  272. a = HH(a, b,      c, d, x[13], S31, 0x289b7ec6L); /* 41 */
  273. d = HH(d, a,      b, c, x[0], S32, 0xeaa127faL); /* 42 */
  274. c = HH(c, d,      a, b, x[3], S33, 0xd4ef3085L); /* 43 */
  275. b = HH(b, c,      d, a, x[6], S34, 0x4881d05L); /* 44 */
  276. a = HH(a, b,      c, d, x[9], S31, 0xd9d4d039L); /* 45 */
  277. d = HH(d, a,      b, c, x[12], S32, 0xe6db99e5L); /* 46 */
  278. c = HH(c, d,      a, b, x[15], S33, 0x1fa27cf8L); /* 47 */
  279. b = HH(b, c,      d, a, x[2], S34, 0xc4ac5665L); /* 48 */
  280.  
  281. /* Round 4 */     
  282. a = II(a, b,      c, d, x[0], S41, 0xf4292244L); /* 49 */
  283. d = II(d, a,      b, c, x[7], S42, 0x432aff97L); /* 50 */
  284. c = II(c, d,      a, b, x[14], S43, 0xab9423a7L); /* 51 */
  285. b = II(b, c,      d, a, x[5], S44, 0xfc93a039L); /* 52 */
  286. a = II(a, b,      c, d, x[12], S41, 0x655b59c3L); /* 53 */
  287. d = II(d, a,      b, c, x[3], S42, 0x8f0ccc92L); /* 54 */
  288. c = II(c, d,      a, b, x[10], S43, 0xffeff47dL); /* 55 */
  289. b = II(b, c,      d, a, x[1], S44, 0x85845dd1L); /* 56 */
  290. a = II(a, b,      c, d, x[8], S41, 0x6fa87e4fL); /* 57 */
  291. d = II(d, a,      b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */
  292. c = II(c, d,      a, b, x[6], S43, 0xa3014314L); /* 59 */
  293. b = II(b, c, d,      a, x[13], S44, 0x4e0811a1L); /* 60 */
  294. a = II(a, b,      c, d, x[4], S41, 0xf7537e82L); /* 61 */
  295. d = II(d, a,      b, c, x[11], S42, 0xbd3af235L); /* 62 */
  296. c = II(c, d,      a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */
  297. b = II(b, c,      d, a, x[9], S44, 0xeb86d391L); /* 64 */
  298.  
  299. state[0] +=      a;
  300. state[1] +=      b;
  301. state[2] +=      c;
  302. state[3] +=      d;
  303.  
  304. }
  305.  
  306. /*Encode把long数组按顺序拆成byte数组,因为java的long类型是64bit的,     
  307. 只拆低32bit,以适应原始C实现的用途
  308. */
  309. private void      Encode(byte[] output, long[] input, int len) {
  310. int i, j;
  311.  
  312. for (i = 0, j      = 0; j < len; i++, j += 4) {
  313. output[j] = (byte)      (input[i] & 0xffL);
  314. output[j + 1]      = (byte) ((input[i] >>> 8) & 0xffL);
  315. output[j + 2]      = (byte) ((input[i] >>> 16) & 0xffL);
  316. output[j + 3]      = (byte) ((input[i] >>> 24) & 0xffL);
  317. }
  318. }
  319.  
  320. /*Decode把byte数组按顺序合成成long数组,因为java的long类型是64bit的,     
  321. 只合成低32bit,高32bit清零,以适应原始C实现的用途
  322. */
  323. private void      Decode(long[] output, byte[] input, int len) {
  324. int i, j;
  325.  
  326. for (i = 0, j      = 0; j < len; i++, j += 4)
  327. output[i] =      b2iu(input[j]) | (b2iu(input[j + 1]) << 8) | (b2iu(input[j + 2])      << 16)
  328. |      (b2iu(input[j + 3]) << 24);
  329.  
  330. return;
  331. }
  332.  
  333. /*
  334. b2iu是我写的一个把byte按照不考虑正负号的原则的"升位"程序,因为java没有unsigned运算
  335. */
  336. public static      long b2iu(byte b) {
  337. return b <      0 ? b & 0x7F + 128 : b;
  338. }
  339.  
  340. /*byteHEX(),用来把一个byte类型的数转换成十六进制的ASCII表示,     
  341.  因为java中的byte的toString无法实现这一点,我们又没有C语言中的
  342. sprintf(outbuf,"%02X",ib)     
  343. */
  344. public static      String byteHEX(byte ib) {
  345. char[] Digit      = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',      'F' };
  346. char[] ob = new      char[2];
  347. ob[0] =      Digit[(ib >>> 4) & 0X0F];
  348. ob[1] =      Digit[ib & 0X0F];
  349. String s = new      String(ob);
  350. return s;
  351. }
  352.  
  353. public static      void main(String args[]) {
  354.  
  355. MD5 m = new      MD5();
  356. if      (Array.getLength(args) == 0) { //如果没有参数,执行标准的Test Suite
  357.  
  358. System.out.println("MD5      Test suite:");
  359. System.out.println("MD5(\"\"):"      + m.getMD5ofStr(""));
  360. System.out.println("MD5(\"a\"):"      + m.getMD5ofStr("a"));
  361. System.out.println("MD5(\"abc\"):"      + m.getMD5ofStr("abc"));
  362. System.out.println("MD5(\"11\"):"      + m.getMD5ofStr("11"));
  363. System.out.println("MD5(\"123\"):"      + m.getMD5ofStr("123"));
  364. System.out.println("MD5(\"message      digest\"):" + m.getMD5ofStr("message digest"));
  365. System.out.println("MD5(\"abcdefghijklmnopqrstuvwxyz\"):"      + m.getMD5ofStr("abcdefghijklmnopqrstuvwxyz"));
  366. System.out.println("MD5(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"):"     
  367. +      m.getMD5ofStr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"));     
  368. } else
  369. System.out.println("MD5("      + args[0] + ")=" + m.getMD5ofStr(args[0]));
  370.  
  371. }
  372.  
  373. }
 

免责声明:文章转载自《java(计算机)常见加密算法详解》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇webpack4与babel配合使es6代码可运行于低版本浏览器Eclipse上搭建Spring的开发环境下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Jsoup使用教程

一、解析和遍历一个HTML文档1、解析Html及Url链接 1 String html = "<html><head><title>First parse</title></head>" 2 + "<body><p>Parsed HTML into a doc.<...

对象Bean与Map互转问题

一、摘要 在实际开发过程中,经常碰到需要进行对象与map之间互转的问题,其实对于对象、Map 之间进行互转有很多种方式,下面我们一起来梳理一下: 利用 JSON 工具包,将对象转成字符串,之后再转成 Map,这种需要转换2次,相对来说效率比较底; 利用 Java 反射,获取 Bean 类的属性和值,再转换到 Map 对应的键值对中,相对来说这种方法效率高...

mybatis-plus总结

mybatis-plus自定义分页、SQL+wrapper一起使用 @Override public Page<TechnologyEnterpriseDto> pageTechnologyEnterprises(TechnologyEnterprisePageReq dto) { QueryWrapper<...

RSA加密与解密

数据信息安全对我们每个人都有很重要的意义,特别是一些敏感信息,可能一些类似于收货地址、手机号还没引起大家的注意。但是最直白的,银行卡、姓名、手机号、身份证号,如果这些信息被黑客拦截到,他就可以伪装成你,把你的钱都取走。那我们该怎么防止这样的事情发生?报文加密解密,加签验签。 我害怕什么 我害怕卡里的钱被别人取走 我害怕转账的时候,报文被黑客拦截到,篡改信息...

iOS--Block的那些事

假设我们熟悉代理递值的话,对代理我们可能又爱有恨!我们先建立模型A页面 push B页面,如果把A页面的值传递到B页面,属性和单例传值可以搞定!但是如果Pop过程中把B页面的值传递到A页面,那就可以用单例或者代理了!说到代理,我们要先声明协议,创建代理,很是麻烦。常常我们传递一个数值需要在两个页面间写很多代码,这些代码改变页面的整体顺序,可读性也打了折扣。...

SpringBoot+读取properties文件内容并注入到类属性中

第一种方法,以发送短信功能为例: 1.application.properties文件: sms.host=http://dingxin.market.alicloudapi.com sms.path=/dx/sendSms sms.method=POST sms.appcode=xxxxxxx 2.需要注入的类,在类的上面加上@Component,在类属...