1
- <!doctype html> < html class ="scroll-pt-16 scroll-smooth " lang =zh > < head > < meta charset =utf-8 > < meta name =viewport content ="width=device-width,initial-scale=1,maximum-scale=1 "> < link rel =icon href ="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'> <text x='0' y='14'>🧑💻</text> </svg> "> < link rel =stylesheet href =https://blog.io01.xyz/css/style.css > < script type =text/javascript src =https://blog.io01.xyz/js/main.js > </ script > < title > MD5 计算前导 0 丢失问题</ title > </ head > < body > < header class ="sticky top-0 z-10 bg-white backdrop-filter backdrop-blur-lg bg-opacity-70 border-b border-gray-200 "> < nav class ="max-w-5xl mx-auto px-4 "> < div class ="flex items-center justify-between h-16 "> < a href =/ class ="text-2xl text-gray-900 font-semibold "> IO01 Blog</ a > < ul class ="flex space-x-4 text-gray-900 "> < li > < a href =https://blog.io01.xyz/posts > 归档</ a > </ li > < li > < a href =https://blog.io01.xyz/about > 关于</ a > </ li > </ ul > </ div > </ nav > </ header > < div id =content > < div class ="flex relative justify-center "> < article class ="w-5/6 md:w-2/3 xl:w-1/2 my-8 px-4 prose max-w-none prose-img:mx-auto "> < header class ="flex flex-col "> < h1 class =text-center > MD5 计算前导 0 丢失问题</ h1 > < div class ="flex-row mx-auto "> < div class =inline-flex > < div class ="inline-flex items-center not-prose "> < svg viewBox ="0 0 1 1 " class ="h-4 mr-1 "> < use href ="#calendar "/> </ svg > < span class =text-gray-500 > 2020-01-20</ span > </ div > < div class ="inline-flex items-center ml-2 not-prose "> < svg viewBox ="0 0 1 1 " class ="h-4 mx-1 "> < use href ="#tags "/> </ svg > < a href =https://blog.io01.xyz/tags/java/ class ="text-gray-500 mr-1 "> Java</ a > </ div > </ div > </ div > </ header > < h2 id =现象 > 现象</ h2 > < p > 我们使用 Java 生成 MD5 时常用的写法如下:</ p > < div class =highlight > < pre tabindex =0 style =color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4 > < code class =language-java data-lang =java > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 1</ span > < span > < span style =color:#8be9fd;font-style:italic > private</ span > < span style =color:#8be9fd;font-style:italic > static</ span > String < span style =color:#50fa7b > md5</ span > < span style =color:#ff79c6 > (</ span > String data< span style =color:#ff79c6 > )</ span > < span style =color:#8be9fd;font-style:italic > throws</ span > NoSuchAlgorithmException < span style =color:#ff79c6 > {</ span >
2
- </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 2</ span > < span > MessageDigest md < span style =color:#ff79c6 > =</ span > MessageDigest< span style =color:#ff79c6 > .</ span > < span style =color:#50fa7b > getInstance</ span > < span style =color:#ff79c6 > (</ span > < span style =color:#f1fa8c > "MD5"</ span > < span style =color:#ff79c6 > );</ span >
3
- </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 3</ span > < span > md< span style =color:#ff79c6 > .</ span > < span style =color:#50fa7b > update</ span > < span style =color:#ff79c6 > (</ span > data< span style =color:#ff79c6 > .</ span > < span style =color:#50fa7b > getBytes</ span > < span style =color:#ff79c6 > ());</ span >
4
- </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 4</ span > < span > < span style =color:#ff79c6 > return</ span > < span style =color:#ff79c6 > new</ span > BigInteger< span style =color:#ff79c6 > (</ span > < span style =color:#bd93f9 > 1</ span > < span style =color:#ff79c6 > ,</ span > md< span style =color:#ff79c6 > .</ span > < span style =color:#50fa7b > digest</ span > < span style =color:#ff79c6 > ()).</ span > < span style =color:#50fa7b > toString</ span > < span style =color:#ff79c6 > (</ span > < span style =color:#bd93f9 > 16</ span > < span style =color:#ff79c6 > );</ span >
5
- </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 5</ span > < span > < span style =color:#ff79c6 > }</ span >
6
- </ span > </ span > </ code > </ pre > </ div > < p > 如果计算 < code > a</ code > 的 MD5 会发现结果为 < code > cc175b9c0f1b6a831c399e269772661</ code > ,只有 31 位,正确的值应该是 < code > 0cc175b9c0f1b6a831c399e269772661</ code > ,仔细观察可以发现我们的计算方法把第一位 < code > 0</ code > 丢失了。</ p > < h2 id =原因 > 原因</ h2 > < p > 原因出在最后的字符串转换上,MD5 生成字符串是将 byte 数组转成了 < code > BigInteger</ code > ,再转成 16 进制表示的字符串,其中转成 < code > BigInteger</ code > 时会丢掉前导 0。</ p > < h2 id =解决 > 解决</ h2 > < p > 只要将字符串生成的地方略作修改即可:</ p > < div class =highlight > < pre tabindex =0 style =color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4 > < code class =language-java data-lang =java > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 1</ span > < span > < span style =color:#8be9fd;font-style:italic > public</ span > < span style =color:#8be9fd;font-style:italic > static</ span > String < span style =color:#50fa7b > md5</ span > < span style =color:#ff79c6 > (</ span > String data< span style =color:#ff79c6 > )</ span > < span style =color:#8be9fd;font-style:italic > throws</ span > NoSuchAlgorithmException < span style =color:#ff79c6 > {</ span >
7
- </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 2</ span > < span > MessageDigest md < span style =color:#ff79c6 > =</ span > MessageDigest< span style =color:#ff79c6 > .</ span > < span style =color:#50fa7b > getInstance</ span > < span style =color:#ff79c6 > (</ span > < span style =color:#f1fa8c > "MD5"</ span > < span style =color:#ff79c6 > );</ span >
8
- </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 3</ span > < span > md< span style =color:#ff79c6 > .</ span > < span style =color:#50fa7b > update</ span > < span style =color:#ff79c6 > (</ span > data< span style =color:#ff79c6 > .</ span > < span style =color:#50fa7b > getBytes</ span > < span style =color:#ff79c6 > ());</ span >
9
- </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 4</ span > < span > < span style =color:#ff79c6 > return</ span > String< span style =color:#ff79c6 > .</ span > < span style =color:#50fa7b > format</ span > < span style =color:#ff79c6 > (</ span > < span style =color:#f1fa8c > "%032x"</ span > < span style =color:#ff79c6 > ,</ span > < span style =color:#ff79c6 > new</ span > BigInteger< span style =color:#ff79c6 > (</ span > < span style =color:#bd93f9 > 1</ span > < span style =color:#ff79c6 > ,</ span > md< span style =color:#ff79c6 > .</ span > < span style =color:#50fa7b > digest</ span > < span style =color:#ff79c6 > ()));</ span >
10
- </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 5</ span > < span > < span style =color:#ff79c6 > }</ span >
11
- </ span > </ span > </ code > </ pre > </ div > < p > < code > String.format</ code > 的参数如下:</ p > < table > < thead > < tr > < th > 转换符或标志</ th > < th > 说明</ th > </ tr > </ thead > < tbody > < tr > < td > %x</ td > < td > 整数类型(十六进制)</ td > </ tr > < tr > < td > 0</ td > < td > 数字前面补 0</ td > </ tr > </ tbody > </ table > < p > 因此当 string 不满 32 位时,自动在前面补 0。</ p > < div class ="flex flex-row justify-between "> < div class =not-prose > < a class ="inline-flex items-center group text-gray-400 hover:text-sky-400 " href =https://blog.io01.xyz/posts/53aj/ > < svg viewBox ="0 0 1 1 " class ="fill-gray-400 group-hover:fill-sky-400 h-4 mx-1 "> < use href ="#angle-left "/> </ svg > 时间格式化的趣事:YYYY 示年</ a > </ div > < div class =not-prose > < a class ="inline-flex items-center group text-gray-400 hover:text-sky-400 " href =https://blog.io01.xyz/posts/57fb/ > 从阿里规约谈起 - 包装类的值比较注意事项< svg viewBox ="0 0 1 1 " class ="fill-gray-400 group-hover:fill-sky-400 h-4 mx-1 "> < use href ="#angle-right "/> </ svg > </ a > </ div > </ div > </ article > </ div > </ div > < footer > < div class ="flex justify-center mt-6 mb-2 text-gray-500 "> < span > ©2023
12
- < span class =ml-2 > < a class =hover:text-sky-400 href =https://blog.io01.xyz > IO01</ a > </ span > </ span >
13
- < span class =mx-2 > |</ span >
1
+ <!doctype html> < html class ="scroll-pt-16 scroll-smooth " lang =zh > < head > < meta charset =utf-8 > < meta name =viewport content ="width=device-width,initial-scale=1,maximum-scale=1 "> < link rel =icon href ="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'> <text x='0' y='14'>🧑💻</text> </svg> "> < link rel =stylesheet href =https://blog.io01.xyz/css/style.css > < script type =text/javascript src =https://blog.io01.xyz/js/main.js > </ script > < title > MD5 计算前导 0 丢失问题</ title > </ head > < body > < header class ="sticky top-0 z-10 bg-white backdrop-filter backdrop-blur-lg bg-opacity-70 border-b border-gray-200 "> < nav class ="max-w-5xl mx-auto px-4 "> < div class ="flex items-center justify-between h-16 "> < a href =/ class ="text-2xl text-gray-900 font-semibold "> IO01 Blog</ a > < ul class ="flex space-x-4 text-gray-900 "> < li > < a href =https://blog.io01.xyz/posts > 归档</ a > </ li > < li > < a href =https://blog.io01.xyz/about > 关于</ a > </ li > </ ul > </ div > </ nav > </ header > < div id =content > < div class ="flex relative justify-center "> < article class ="w-5/6 md:w-2/3 xl:w-1/2 my-8 px-4 prose max-w-none prose-img:mx-auto "> < header class ="flex flex-col "> < h1 class =text-center > MD5 计算前导 0 丢失问题</ h1 > < div class ="flex-row mx-auto "> < div class =inline-flex > < div class ="inline-flex items-center not-prose "> < svg viewBox ="0 0 1 1 " class ="h-4 mr-1 "> < use href ="#calendar "/> </ svg >
2
+ < span class =text-gray-500 > 2020-01-20</ span > </ div > < div class ="inline-flex items-center ml-2 not-prose "> < svg viewBox ="0 0 1 1 " class ="h-4 mx-1 "> < use href ="#tags "/> </ svg >
3
+ < a href =https://blog.io01.xyz/tags/java/ class ="text-gray-500 mr-1 "> Java</ a > </ div > </ div > </ div > </ header > < h2 id =现象 > 现象</ h2 > < p > 我们使用 Java 生成 MD5 时常用的写法如下:</ p > < div class =highlight > < pre tabindex =0 style =color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4 > < code class =language-java data-lang =java > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 1</ span > < span > < span style =color:#8be9fd;font-style:italic > private</ span > < span style =color:#8be9fd;font-style:italic > static</ span > String < span style =color:#50fa7b > md5</ span > (String data) < span style =color:#8be9fd;font-style:italic > throws</ span > NoSuchAlgorithmException {
4
+ </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 2</ span > < span > MessageDigest md < span style =color:#ff79c6 > =</ span > MessageDigest.< span style =color:#50fa7b > getInstance</ span > (< span style =color:#f1fa8c > "MD5"</ span > );
5
+ </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 3</ span > < span > md.< span style =color:#50fa7b > update</ span > (data.< span style =color:#50fa7b > getBytes</ span > ());
6
+ </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 4</ span > < span > < span style =color:#ff79c6 > return</ span > < span style =color:#ff79c6 > new</ span > BigInteger(1, md.< span style =color:#50fa7b > digest</ span > ()).< span style =color:#50fa7b > toString</ span > (16);
7
+ </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 5</ span > < span > }
8
+ </ span > </ span > </ code > </ pre > </ div > < p > 如果计算 < code > a</ code > 的 MD5 会发现结果为 < code > cc175b9c0f1b6a831c399e269772661</ code > ,只有 31 位,正确的值应该是 < code > 0cc175b9c0f1b6a831c399e269772661</ code > ,仔细观察可以发现我们的计算方法把第一位 < code > 0</ code > 丢失了。</ p > < h2 id =原因 > 原因</ h2 > < p > 原因出在最后的字符串转换上,MD5 生成字符串是将 byte 数组转成了 < code > BigInteger</ code > ,再转成 16 进制表示的字符串,其中转成 < code > BigInteger</ code > 时会丢掉前导 0。</ p > < h2 id =解决 > 解决</ h2 > < p > 只要将字符串生成的地方略作修改即可:</ p > < div class =highlight > < pre tabindex =0 style =color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4 > < code class =language-java data-lang =java > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 1</ span > < span > < span style =color:#8be9fd;font-style:italic > public</ span > < span style =color:#8be9fd;font-style:italic > static</ span > String < span style =color:#50fa7b > md5</ span > (String data) < span style =color:#8be9fd;font-style:italic > throws</ span > NoSuchAlgorithmException {
9
+ </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 2</ span > < span > MessageDigest md < span style =color:#ff79c6 > =</ span > MessageDigest.< span style =color:#50fa7b > getInstance</ span > (< span style =color:#f1fa8c > "MD5"</ span > );
10
+ </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 3</ span > < span > md.< span style =color:#50fa7b > update</ span > (data.< span style =color:#50fa7b > getBytes</ span > ());
11
+ </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 4</ span > < span > < span style =color:#ff79c6 > return</ span > String.< span style =color:#50fa7b > format</ span > (< span style =color:#f1fa8c > "%032x"</ span > , < span style =color:#ff79c6 > new</ span > BigInteger(1, md.< span style =color:#50fa7b > digest</ span > ()));
12
+ </ span > </ span > < span style =display:flex > < span style ="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f "> 5</ span > < span > }
13
+ </ span > </ span > </ code > </ pre > </ div > < p > < code > String.format</ code > 的参数如下:</ p > < table > < thead > < tr > < th > 转换符或标志</ th > < th > 说明</ th > </ tr > </ thead > < tbody > < tr > < td > %x</ td > < td > 整数类型(十六进制)</ td > </ tr > < tr > < td > 0</ td > < td > 数字前面补 0</ td > </ tr > </ tbody > </ table > < p > 因此当 string 不满 32 位时,自动在前面补 0。</ p > < div class ="flex flex-row justify-between "> < div class =not-prose > < a class ="inline-flex items-center group text-gray-400 hover:text-sky-400 " href =https://blog.io01.xyz/posts/53aj/ > < svg viewBox ="0 0 1 1 " class ="fill-gray-400 group-hover:fill-sky-400 h-4 mx-1 "> < use href ="#angle-left "/> </ svg >
14
+ 时间格式化的趣事:YYYY 示年</ a > </ div > < div class =not-prose > < a class ="inline-flex items-center group text-gray-400 hover:text-sky-400 " href =https://blog.io01.xyz/posts/57fb/ > 从阿里规约谈起 - 包装类的值比较注意事项< svg viewBox ="0 0 1 1 " class ="fill-gray-400 group-hover:fill-sky-400 h-4 mx-1 "> < use href ="#angle-right "/> </ svg > </ a > </ div > </ div > </ article > </ div > </ div > < footer > < div class ="flex justify-center mt-6 mb-2 text-gray-500 "> < span > ©2024
15
+ < span class =ml-2 > < a class =hover:text-sky-400 href =https://blog.io01.xyz > IO01</ a >
16
+ </ span > </ span > < span class =mx-2 > |</ span >
14
17
< span > Powered by
15
- < a class =hover:text-sky-400 href =https://gohugo.io > Hugo</ a > </ span >
16
- < span class =mx-1 > &</ span >
18
+ < a class =hover:text-sky-400 href =https://gohugo.io > Hugo</ a >
19
+ </ span > < span class =mx-1 > &</ span >
17
20
< span > < a class =hover:text-sky-400 href =# > FullMoon</ a > </ span > </ div > </ footer > </ body > </ html >
0 commit comments