当前位置: 主页 > JAVA语言

java md5加密代码-java实现md5加密代码

发布时间:2023-03-23 11:23   浏览次数:次   作者:佚名

java 文件md5加密_java md5加密代码_java实现md5加密代码

立即加星标

java md5加密代码_java 文件md5加密_java实现md5加密代码

每天看好文

目录

一、前言介绍

二、参数分析

三、堆栈调试

四、算法分析

五、思路总结

趣味模块

小军是一名工程师,最近小军遇到了一个棘手的问题:小军想要还原一个加密算法,他不想和往常一样通过Python调用JS的方式去实现算法还原;而是选择通过Python、Go、Java语言去实现算法还原。这篇文章中,我们将解决小军遇到的困境,让我们一起去看小军遇到的难题并通过多种语言去实现算法还原吧!

一、前言介绍

1、什么是md5加密?

MD5消息摘要算法(MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5加密是一种不可逆的加密算法,不可逆加密算法的特征是加密过程中不需要使用密钥,输入明文后由系统直接经过加密算法处理成密文,这种加密后的数据是无法被解密的,只有重新输入明文,并再次经过同样不可逆的加密算法处理,得到相同的加密密文并被系统重新识别后,才能真正解密。

2、md5是如何加密的?

MD5算法的原理可简要的叙述为:MD5码以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

总体流程如下图所示,每次的运算都由前一轮的128位结果值和当前的512bit值进行运算。

java实现md5加密代码_java md5加密代码_java 文件md5加密

了解了md5加密后,接下来我们去实战中分析md5是如何实现魔改并进行加密运算的。

二、参数分析

1、首先打开我们今天要模拟的网站,刷新当前页面,使用fn+F12打开开发者界面,直接定位我们要获取的接口java md5加密代码,截图如下所示:

java实现md5加密代码_java 文件md5加密_java md5加密代码

2、我们确定好获取的接口后,点击payload查看该请求参数,截图如下所示:

java实现md5加密代码_java 文件md5加密_java md5加密代码

3、标红的参数就是我们本次要还原的加密参数,接下来,我们对该接口各个参数进行初判断及整理分析:

Data参数分析:

Headers参数分析:

说明:由于headers参数没有重要参数影响,故不作说明。

ormData

三、断点调试

1、使用最简单的方式,查询指定关键字、加密方法,定位加密参数具体坐标文件,截图如下:

java md5加密代码_java 文件md5加密_java实现md5加密代码

说明:经过查询,我们可以肯定的是代码中没有用到这个变量名,然后我们去搜索加密方法,发现能搜到结果,但是和我们的加密参数关联不大,截图如下:

java md5加密代码_java 文件md5加密_java实现md5加密代码

2、接下来,我们还是使用XHR打断点,回溯堆栈的方式查找吧,截图如下:

java实现md5加密代码_java 文件md5加密_java md5加密代码

3、然后刷新当前页面,进行堆栈查找,截图如下:

java实现md5加密代码_java md5加密代码_java 文件md5加密

总结:很明显此刻加密参数已经生成,我们需要定位参数生成的位置,就需要学会查看堆栈信息,接下里进行堆栈回溯。

4、通过Call Stack进行堆栈回溯,截图如下所示:

java md5加密代码_java实现md5加密代码_java 文件md5加密

5、由于堆栈回溯流程环节较多,我们直接快进定位到加密参数位置,截图如下:

java实现md5加密代码_java md5加密代码_java 文件md5加密

说明:此刻我们可以看到t参数为timetamp参数拼接salt参数,然后进行下面参数运行即可得到第一次加密的密文,截图如下所示:

java实现md5加密代码_java md5加密代码_java 文件md5加密

总结:此刻我们验证下前面的猜想:是否是md5加密,将明文信息粘贴到md5在线生成工具中验证,结果和js生成的值不匹配,截图如下:

java 文件md5加密_java md5加密代码_java实现md5加密代码

6、继续执行断点,我们可以看到第二次加密运行截图如下图所示:

java md5加密代码_java 文件md5加密_java实现md5加密代码

总结:此刻我们可以看到第二次加密运行的入参为:formDataStr拼接刚刚加密运行得到密文的32位字符串。继续执行断点,截图如下图所示:

java md5加密代码_java实现md5加密代码_java 文件md5加密

7、将JS断点调试生成的最终加密值,与xhr请求时发送的formDataSign加密值对比,截图如下:

java实现md5加密代码_java 文件md5加密_java md5加密代码

总结:我们可以看到formDataSign的值是经过两轮js自定义魔改算法而生成的java md5加密代码,接下来我们通过还原js加密算法去验证该网站是否使用的魔改md5。

四、算法还原

1、先将本次分析的js代码抠出来使用Nodejs运行,去掉一些无用代码后,完整代码如下:

function encrypt(e) {    function h(a, b) {        var c, d, e, f, g;        e = a & 2147483648;        f = b & 2147483648;        c = a & 1073741824;        d = b & 1073741824;        g = (a & 1073741823) + (b & 1073741823);        return c & d ? g ^ 2147483648 ^ e ^ f : c | d ? g & 1073741824 ? g ^ 3221225472 ^ e ^ f : g ^ 1073741824 ^ e ^ f : g ^ e ^ f    }
function k(a, b, c, d, e, f, g) { a = h(a, h(h(b & c | ~b & d, e), g)); return h(a << f | a >>> 32 - f, b) }
function l(a, b, c, d, e, f, g) { a = h(a, h(h(b & d | c & ~d, e), g)); return h(a << f | a >>> 32 - f, b) }
function m(a, b, d, c, e, f, g) { a = h(a, h(h(b ^ d ^ c, e), g)); return h(a << f | a >>> 32 - f, b) }
function n(a, b, d, c, e, f, g) { a = h(a, h(h(d ^ (b | ~c), e), g)); return h(a << f | a >>> 32 - f, b) }
function p(a) { var b = "", d = "", c; for (c = 0; 3 >= c; c++) d = a >>> 8 * c & 255, d = "0" + d.toString(16), b += d.substr(d.length - 2, 2); return b }
var f = [], q, r, s, t, a, b, c, d; e = function (a) { a = a.replace(/\\r\\n/g, "\\n"); for (var b = "", d = 0; d < a.length; d++) { var c = a.charCodeAt(d); 128 > c ? b += String.fromCharCode(c) : (127 < c && 2048 > c ? b += String.fromCharCode(c >> 6 | 192) : (b += String.fromCharCode(c >> 12 | 224), b += String.fromCharCode(c >> 6 & 63 | 128)), b += String.fromCharCode(c & 63 | 128)) } return b }(e); f = function (b) { var a, c = b.length; a = c + 8; for (var d = 16 * ((a - a % 64) / 64 + 1), e = Array(d - 1), f = 0, g = 0; g < c;) a = (g - g % 4) / 4, f = g % 4 * 8, e[a] |= b.charCodeAt(g) << f, g++; a = (g - g % 4) / 4; e[a] |= 128 << g % 4 * 8; e[d - 2] = c << 3; e[d - 1] = c >>> 29; return e }(e); a = 271733878; b = 2562383102; c = 4023233417; d = 1732584193; for (e = 0; e < f.length; e += 16) q = a, r = b, s = c, t = d, a = k(a, b, c, d, f[e + 0], 7, 3614090360), d = k(d, a, b, c, f[e + 1], 12, 3905402710), c = k(c, d, a, b, f[e + 2], 17, 606105819), b = k(b, c, d, a, f[e + 3], 22, 3250441966), a = k(a, b, c, d, f[e + 4], 7, 4118548399), d = k(d, a, b, c, f[e + 5], 12, 1200080426), c = k(c, d, a, b, f[e + 6], 17, 2821735955), b = k(b, c, d, a, f[e + 7], 22, 4249261313), a = k(a, b, c, d, f[e + 8], 7, 1770035416), d = k(d, a, b, c, f[e + 9], 12, 2336552879), c = k(c, d, a, b, f[e + 10], 17, 4294925233), b = k(b, c, d, a, f[e + 11], 22, 2304563134), a = k(a, b, c, d, f[e + 12], 7, 1804603682), d = k(d, a, b, c, f[e + 13], 12, 4254626195), c = k(c, d, a, b, f[e + 14], 17, 2792965006), b = k(b, c, d, a, f[e + 15], 22, 1236535329), a = l(a, b, c, d, f[e + 1], 5, 4129170786), d = l(d, a, b, c, f[e + 6], 9, 3225465664), c = l(c, d, a, b, f[e + 11], 14, 643717713), b = l(b, c, d, a, f[e + 0], 20, 3921069994), a = l(a, b, c, d, f[e + 5], 5, 3593408605), d = l(d, a, b, c, f[e + 10], 9, 38016083), c = l(c, d, a, b, f[e + 15], 14, 3634488961), b = l(b, c, d, a, f[e + 4], 20, 3889429448), a = l(a, b, c, d, f[e + 9], 5, 568446438), d = l(d, a, b, c, f[e + 14], 9, 3275163606), c = l(c, d, a, b, f[e + 3], 14, 4107603335), b = l(b, c, d, a, f[e + 8], 20, 1163531501), a = l(a, b, c, d, f[e + 13], 5, 2850285829), d = l(d, a, b, c, f[e + 2], 9, 4243563512), c = l(c, d, a, b, f[e + 7], 14, 1735328473), b = l(b, c, d, a, f[e + 12], 20, 2368359562), a = m(a, b, c, d, f[e + 5], 4, 4294588738), d = m(d, a, b, c, f[e + 8], 11, 2272392833), c = m(c, d, a, b, f[e + 11], 16, 1839030562), b = m(b, c, d, a, f[e + 14], 23, 4259657740), a = m(a, b, c, d, f[e + 1], 4, 2763975236), d = m(d, a, b, c, f[e + 4], 11, 1272893353), c = m(c, d, a, b, f[e + 7], 16, 4139469664), b = m(b, c, d, a, f[e + 10], 23, 3200236656), a = m(a, b, c, d, f[e + 13], 4, 681279174), d = m(d, a, b, c, f[e + 0], 11, 3936430074), c = m(c, d, a, b, f[e + 3], 16, 3572445317), b = m(b, c, d, a, f[e + 6], 23, 76029189), a = m(a, b, c, d, f[e + 9], 4, 3654602809), d = m(d, a, b, c, f[e + 12], 11, 3873151461), c = m(c, d, a, b, f[e + 15], 16, 530742520), b = m(b, c, d, a, f[e + 2], 23, 3299628645), a = n(a, b, c, d, f[e + 0], 6, 4096336452), d = n(d, a, b, c, f[e + 7], 10, 1126891415), c = n(c, d, a, b, f[e + 14], 15, 2878612391), b = n(b, c, d, a, f[e + 5], 21, 4237533241), a = n(a, b, c, d, f[e + 12], 6, 1700485571), d = n(d, a, b, c, f[e + 3], 10, 2399980690), c = n(c, d, a, b, f[e + 10], 15, 4293915773), b = n(b, c, d, a, f[e + 1], 21, 2240044497), a = n(a, b, c, d, f[e + 8], 6, 1873313359), d = n(d, a, b, c, f[e + 15], 10, 4264355552), c = n(c, d, a, b, f[e + 6], 15, 2734768916), b = n(b, c, d, a, f[e + 13], 21, 1309151649), a = n(a, b, c, d, f[e + 4], 6, 4149444226), d = n(d, a, b, c, f[e + 11], 10, 3174756917), c = n(c, d, a, b, f[e + 2], 15, 718787259), b = n(b, c, d, a, f[e + 9], 21, 3951481745), a = h(a, q), b = h(b, r), c = h(c, s), d = h(d, t); return (p(a) + p(b) + p(c) + p(d)).toLowerCase()};var params = "16774142142710df14fccd4ef73ee9d59451a6c2fb";var first_md5 = encrypt(params);var keyword = '{"keyword":"三只羊"}' + first_md5;var last_md5 = encrypt(keyword);console.log(last_md5);

1.1 代码运行后截图如下:

java md5加密代码_java实现md5加密代码_java 文件md5加密

总结:通过还原js代码,我们已经能够解决小军提到的问题。大家肯定很好奇,为啥我知道该网站使用的算法是魔改md5加密算法,很简单的一步操作就是先看常量(a、b、c、d),再看码表K。很明显这个地方的a、b、c、d四个常量转为16进制后,是经过了特殊的魔改而来。接下来让我们用其他语言来实现该算法吧!

2、经过上面的深度分析后,我通过修改md5源码实现了一版Python魔改的md5算法,完整代码如下:

# -*- coding: utf-8 -*-# -------------------------# @author : 逆向与爬虫的故事# -------------------------def magic_md5(message: str) -> bytes:    # 定义常量,用于初始化128位变量,注意字节顺序,A=0x01234567,这里低值存放低字节,    # 即01 23 45 67,所以运算时A=0x67452301,其他类似。    # 用字符串的形势,是为了和hex函数的输出统一,hex(10)输出为'0xA',注意结果为字符串。    h0 = 0x10325476    h1 = 0x98badcfe    h2 = 0xefcdab89    h3 = 0x67452301
# 定义每轮中循环左移的位数,用元组表示 4*4*4=64 R = (7, 12, 17, 22) * 4 + (5, 9, 14, 20) * 4 + \ (4, 11, 16, 23) * 4 + (6, 10, 15, 21) * 4 # 定义常数K 64 # K[i] = (int(abs(math.sin(i + 1)) * 2 ** 32)) & 0xffffffff K = (0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391)
# 定义每轮中用到的函数。L为循环左移, # 左移之后可能会超过32位,所以要和0xffffffff做与运算,确保结果为32位。 F = lambda x, y, z: ((x & y) | ((~x) & z)) G = lambda x, y, z: ((x & z) | (y & (~z))) H = lambda x, y, z: (x ^ y ^ z) I = lambda x, y, z: (y ^ (x | (~z)))
L = lambda x, n: ((x << n) | (x >> (32 - n))) & 0xffffffff # 小端 0x12,0x34,0x56,0x78 -> 0x78563412 # 将四个8位无符号数转化为一个32位无符号数 W = lambda i4, i3, i2, i1: (i1 << 24) | (i2 << 16) | (i3 << 8) | i4 # 字节翻转 0x12345678 -> 0x78563412 将一个32位无符号数的高位和低位进行对换 reverse = lambda x: (x << 24) & 0xff000000 | (x << 8) & 0x00ff0000 | \ (x >> 8) & 0x0000ff00 | (x >> 24) & 0x000000ff

# 对每一个输入先添加一个'0x80',即'10000000', 即128 ascii_list = list(map(lambda x: x, message.encode())) msg_length = len(ascii_list) * 8 ascii_list.append(128)
# 补充0 while (len(ascii_list) * 8 + 64) % 512 != 0: ascii_list.append(0)
# 最后64为存放消息长度,以小端数存放。 # 例如,消息为'a',则长度是8,则添加'0x0800000000000000' for i in range(8): ascii_list.append((msg_length >> (8 * i)) & 0xff)
# print(ascii_list) # print(len(ascii_list)//64) # 对每一消息块进行迭代 for i in range(len(ascii_list) // 64): # print(ascii_list[i*64:(i+1)*64]) # 对每一个消息块进行循环,每个消息块512bits=16*32bits=64*8bits a, b, c, d = h0, h1, h2, h3 for j in range(64): # 64轮的主循环 if 0 <= j <= 15: f = F(b, c, d) & 0xffffffff g = j elif 16 <= j <= 31: f = G(b, c, d) & 0xffffffff g = ((5 * j) + 1) % 16 elif 32 <= j <= 47: f = H(b, c, d) & 0xffffffff g = ((3 * j) + 5) % 16 else: f = I(b, c, d) & 0xffffffff g = (7 * j) % 16 aa, dd, cc = d, c, b # 第i个chunk,第g个32-bit s = i * 64 + g * 4 w = W(ascii_list[s], ascii_list[s + 1], ascii_list[s + 2], ascii_list[s + 3]) bb = (L((a + f + K[j] + w) & 0xffffffff, R[j]) + b) & 0xffffffff a, b, c, d = aa, bb, cc, dd # print(b) h0 = (h0 + a) & 0xffffffff h1 = (h1 + b) & 0xffffffff h2 = (h2 + c) & 0xffffffff h3 = (h3 + d) & 0xffffffff h0, h1, h2, h3 = reverse(h0), reverse(h1), reverse(h2), reverse(h3) digest = (h0 << 96) | (h1 << 64) | (h2 << 32) | h3 return hex(digest)[2:].rjust(32, '0')

2.1 代码运行后截图如下:

java 文件md5加密_java实现md5加密代码_java md5加密代码

3、为了满足小军的需求,我们又实现了一版Go语言版本的魔改md5算法,完整代码如下:

package md5
import ( "crypto" "encoding/binary" "errors" "hash")
func init() { crypto.RegisterHash(crypto.MD5, New)}
// The size of an MD5 checksum in bytes.const Size = 16
// The blocksize of MD5 in bytes.const BlockSize = 64
const ( init0 = 0x10325476 init1 = 0x98badcfe init2 = 0xefcdab89 init3 = 0x67452301)
// digest represents the partial evaluation of a checksum.type digest struct { s [4]uint32 x [BlockSize]byte nx int len uint64}
func (d *digest) Reset() { d.s[0] = init0 d.s[1] = init1 d.s[2] = init2 d.s[3] = init3 d.nx = 0 d.len = 0}
const ( magic = "md5\x01" marshaledSize = len(magic) + 4*4 + BlockSize + 8)
func (d *digest) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize) b = append(b, magic...) b = appendUint32(b, d.s[0]) b = appendUint32(b, d.s[1]) b = appendUint32(b, d.s[2]) b = appendUint32(b, d.s[3]) b = append(b, d.x[:d.nx]...) b = b[:len(b)+len(d.x)-d.nx] // already zero b = appendUint64(b, d.len) return b, nil}
func (d *digest) UnmarshalBinary(b []byte) error { if len(b) < len(magic) || string(b[:len(magic)]) != magic { return errors.New("crypto/md5: invalid hash state identifier") } if len(b) != marshaledSize { return errors.New("crypto/md5: invalid hash state size") } b = b[len(magic):] b, d.s[0] = consumeUint32(b) b, d.s[1] = consumeUint32(b) b, d.s[2] = consumeUint32(b) b, d.s[3] = consumeUint32(b) b = b[copy(d.x[:], b):] b, d.len = consumeUint64(b) d.nx = int(d.len % BlockSize) return nil}
func appendUint64(b []byte, x uint64) []byte { var a [8]byte binary.BigEndian.PutUint64(a[:], x) return append(b, a[:]...)}
func appendUint32(b []byte, x uint32) []byte { var a [4]byte binary.BigEndian.PutUint32(a[:], x) return append(b, a[:]...)}
func consumeUint64(b []byte) ([]byte, uint64) { return b[8:], binary.BigEndian.Uint64(b[0:8])}
func consumeUint32(b []byte) ([]byte, uint32) { return b[4:], binary.BigEndian.Uint32(b[0:4])}
// New returns a new hash.Hash computing the MD5 checksum. The Hash also// implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to// marshal and unmarshal the internal state of the hash.func New() hash.Hash { d := new(digest) d.Reset() return d}
func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) { // Note that we currently call block or blockGeneric // directly (guarded using haveAsm) because this allows // escape analysis to see that p and d don't escape. nn = len(p) d.len += uint64(nn) if d.nx > 0 { n := copy(d.x[d.nx:], p) d.nx += n if d.nx == BlockSize { if haveAsm { block(d, d.x[:]) } else { blockGeneric(d, d.x[:]) } d.nx = 0 } p = p[n:] } if len(p) >= BlockSize { n := len(p) &^ (BlockSize - 1) if haveAsm { block(d, p[:n]) } else { blockGeneric(d, p[:n]) } p = p[n:] } if len(p) > 0 { d.nx = copy(d.x[:], p) } return}
func (d *digest) Sum(in []byte) []byte { // Make a copy of d so that caller can keep writing and summing. d0 := *d hash := d0.checkSum() return append(in, hash[:]...)}
func (d *digest) checkSum() [Size]byte { // Append 0x80 to the end of the message and then append zeros // until the length is a multiple of 56 bytes. Finally append // 8 bytes representing the message length in bits. // // 1 byte end marker :: 0-63 padding bytes :: 8 byte length tmp := [1 + 63 + 8]byte{0x80} pad := (55 - d.len) % 64 // calculate number of padding bytes binary.LittleEndian.PutUint64(tmp[1+pad:], d.len<<3) // append length in bits d.Write(tmp[:1+pad+8])
// The previous write ensures that a whole number of // blocks (i.e. a multiple of 64 bytes) have been hashed. if d.nx != 0 { panic("d.nx != 0") }
var digest [Size]byte binary.LittleEndian.PutUint32(digest[0:], d.s[0]) binary.LittleEndian.PutUint32(digest[4:], d.s[1]) binary.LittleEndian.PutUint32(digest[8:], d.s[2]) binary.LittleEndian.PutUint32(digest[12:], d.s[3]) return digest}
// Sum returns the MD5 checksum of the data.func Sum(data []byte) [Size]byte { var d digest d.Reset() d.Write(data) return d.checkSum()}

3.1 main函数完整代码如下:

package main
import ( "collyx-spider/utils/md5" "fmt")
func main() { firstText := "16774142142710df14fccd4ef73ee9d59451a6c2fb" signBytes := md5.Sum([]byte(firstText)) sign := fmt.Sprintf("%x", signBytes) fmt.Println(sign) secondText := `{"keyword":"三只羊"}` + sign sign2Bytes := md5.Sum([]byte(secondText)) lastSign := fmt.Sprintf("%x", sign2Bytes) fmt.Println(lastSign)}

3.2 代码运行后,截图如下所示:

java实现md5加密代码_java md5加密代码_java 文件md5加密

总结:观察Goland生成的加密值,我们可以确定和前面计算的结果一致,接下来我们再研究下java版本魔改md5如何实现。

4、作者通过Java语言实现的魔改md5完整代码如下:


import java.util.Arrays;
public class MagicMd5 { private String content; private String md5;

public String md5(String text) { content = text; this.Reset(); return md5; }
private void Reset() { int[] init = new int[]{0x10325476, 0x98badcfe, 0xefcdab89, 0x67452301};
byte[] bytes = new byte[64]; byte[] tail = new byte[0]; int len = 0; long size = 0; byte[] src = content.getBytes(); int n = src.length / 64; for (int i = 0; i < n; i++) { bytes = Arrays.copyOfRange(src, i * 64, i * 64 + 64); init = md5_2(bytes, init); } size = src.length * 8; tail = Arrays.copyOfRange(src, src.length - src.length % 64, src.length);

if (tail.length < 56) { bytes = Arrays.copyOf(tail, 64); bytes[tail.length] = -128; } else { bytes = Arrays.copyOf(tail, 64); bytes[tail.length] = -128; init = md5_2(bytes, init); bytes = Arrays.copyOf(new byte[]{}, 64); } for (int i = 0; i < 8; i++) { bytes[56 + i] = new Long(size >>> i * 8).byteValue(); } init = md5_2(bytes, init); md5 = int2string(init[0]) + int2string(init[1]) + int2string(init[2]) + int2string(init[3]); }
public int[] md5_2(byte[] bytes, int[] before) { int A = before[0], B = before[1], C = before[2], D = before[3]; int a = A, b = B, c = C, d = D; int s[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; int[] k = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
for (int i = 0; i < 64; i++) { int f, g; if (i < 16) { f = (b & c) | (~b & d); g = i; } else if (i < 32) { f = (b & d) | (~d & c); g = (5 * i + 1) % 16; } else if (i < 48) { f = b ^ c ^ d; g = (3 * i + 5) % 16; } else { f = c ^ (~d | b); g = 7 * i % 16; }
int m = byteArr2Int(Arrays.copyOfRange(bytes, 4 * g, 4 * g + 4)); int b_temp = b; b = b + Integer.rotateLeft(a + f + m + k[i], s[i]); a = d; d = c; c = b_temp; } A += a; B += b; C += c; D += d;
int[] res = new int[4]; res[0] = A; res[1] = B; res[2] = C; res[3] = D;
return res; }
public String int2string(int n) { String res = ""; for (int i = 0; i < 4; i++) { String s = (Integer.toHexString((n >>> (8 * i)) & 0xff)); if (s.length() < 2) { s = "0" + s; } res += s; } return res; }
private int byteArr2Int(byte[] bytes) { int res = 0; for (int i = 3; i >= 0; i--) { res = (res << 8); res += (int) bytes[i] & 0xff; } return res; }

@Override public String toString() { return "MD5 [content=" + content + "]"; }
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((content == null) ? 0 : content.hashCode()); return result; }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MagicMd5 other = (MagicMd5) obj; if (content == null) { if (other.content != null) return false; } else if (!content.equals(other.content)) return false; return true; }
public static void main(String[] args) { // 运行魔改md5加密算法 MagicMd5 magicmd5 = new MagicMd5(); String firstSign = magicmd5.md5("16774142142710df14fccd4ef73ee9d59451a6c2fb"); String keyword = "{\"keyword\":\"三只羊\"}"; System.out.println(firstSign); String lastSign = magicmd5.md5(keyword+firstSign); System.out.println(lastSign); }
}

4.1 代码实现后,我们将运行后的代码截图如下所示:

java 文件md5加密_java md5加密代码_java实现md5加密代码

总结:本篇文章到这里,我们已经能够通过Js、Python、Go、Java语言去实现魔改md5算法还原了,小军遇到的难题我们已经迎刃而解,整篇文章字数有点多,感谢大家耐心观看!

五、思路总结

回顾整个分析流程,本次难点主要概括为以下几点: