使用MD5算法对ANDROID SQLITE中的内容进行加密
java,android,MD5加密算法的实现代码(16位,32位)

public static String getMD5(String val) throws NoSuchAlgorithmException{ MessageDigest md5 = MessageDigest.getInstance("MD5"); md5.update(val.getBytes()); byte[] m = md5.digest();//加密 return getString(m);
} private static String getString(byte[] b){
StringBuffer buf = new StringBuffer(); for(int i = 0; i < b.length; i ++){ int a = b[i]; if(a<0)
a+=256; if(a<16) buf.append("0"); buf.append(Integer.toHexString(a));
} return buf.toString(); //32位 或者 return buf.toString().substring(8,24); //16位
以上就是小编为大家带来的java,android,MD5加密算法的实现代码(16位,32位)的全部内容了,希望对大家有所帮助,多多支持 ~
这篇文章主要给大家介绍了关于java实现矩阵乘法以及优化的相关资料文中通过示例代码介绍的非常详细对大家的学习或者工作具有一定的参考学习价值需要的朋友们下面随着小编来一起学习学习吧
java,android,MDort java.security.MessageDigest; import java.security.NoSuchAlgorithmException;
md5加密规则

md5加密规则
MD5加密规则
MD5加密是一种常见的数据加密方式,被广泛应用于网络安全领域中,用来保护数据的安全性和完整性。
MD5加密具有以下规则:
1. 明文转换:将明文(需要加密的原始数据)转换成二进制数据格式,然后对其进行一系列的加密处理。
2. 加密过程:MD5加密的过程通过四轮运算来完成。
每轮运算具有不同的计算方式,通过四轮运算得到的结果最终生成128位的密文。
3. 不可逆性:MD5算法采用的是不可逆加密方式,即通过密文无法还原出明文。
相同的明文总是会生成相同的密文,但不同的明文生成的
密文是不同的。
4. 安全性:MD5算法本身具有一定的强度,但也存在一些弱点。
例如,由于MD5算法的安全性问题,Google Chrome浏览器不再支持使用此算法的数字证书,而是采用更安全的SHA-1算法。
MD5加密在网络安全领域中扮演着重要的角色,它能够对数据进行保
护和加密,实现对数据的安全传输和存储。
但是随着计算技术的发展和算法的弱点被攻破,MD5算法变得越来越不安全,人们也开始寻找更为安全的加密方式来保护数据的安全性。
MD5加密概述原理以及实现

MD5加密概述原理以及实现MD5(Message Digest Algorithm 5)是一种常用的哈希函数,用于将任意长度的数据转换为固定长度的哈希值。
在网络传输和数据存储中,MD5广泛用于校验数据完整性,验证密码以及防止篡改等场景。
1.哈希值固定长度:无论输入数据的长度是多少,MD5算法生成的哈希值都是128位(16字节)的二进制数字。
2.唯一性:在理论上,MD5生成的哈希值应该是唯一的。
也就是说,不同的输入数据生成的哈希值不会相同。
3.不可逆性:MD5是一种单向函数,即无法通过从哈希值反向推导出原始数据。
只能通过对比不同数据的哈希值来判断其是否相同。
MD5算法的实现过程可以分为以下几个步骤:1.填充数据:将输入数据按字节切分成512位的数据段,并在数据段末尾填充一定数量的0,使其长度能被512整除。
2.初始化缓冲区:定义四个32位的缓冲区(A、B、C、D),作为算法计算的中间结果。
3.处理数据段:对每个数据段进行相同的处理流程,包括四轮的循环压缩和变换操作。
4.输出结果:将最后一次处理后的缓冲区内容按顺序连接起来,形成128位的MD5哈希值。
具体的实现细节如下:1.填充数据:如果输入数据的长度不能被512整除,就在末尾填充一个1和若干个0,使得填充后的长度满足对512取余等于448、之后,再在末尾追加64位的原始数据长度,以二进制形式表示。
2.初始化缓冲区:将四个32位的缓冲区(A、B、C、D)初始化为固定的初始值。
3.处理数据段:将每个数据段分为16个32位的子块,对每个子块进行以下四轮的循环压缩和变换操作。
-第一轮循环:通过对字节数组进行位运算,将每个子块与缓冲区中的四个值进行一系列的逻辑运算,然后更新缓冲区的值。
-第二轮循环:将第一轮循环得到的缓冲区值重新排列并加上一个常量,然后再进行一系列的逻辑运算。
-第三轮循环:将第二轮循环得到的缓冲区值再次进行一系列的逻辑运算。
-第四轮循环:将第三轮循环得到的缓冲区值再次进行一系列的逻辑运算。
MD5加密操作

return sb.ToString();
}
我可以在主窗体调用
private void btnexit_Click(object sender, EventArgs e) { Md5加密 md = new Md5加密(); string num= md.GetMD5String("1"); MessageBox.Show(num); }
MD5加密字符串
方式一:
public string GetMD5String(string pwd) { MD5CryptoServiceProvider md5=new MD5CryptoServiceProvide(); byte[] data=System.Text.Encoding.ASCII.GetBytes(pwd); byte[] md5data=puteHash(data); StringBuilder builder=new StringBUilder(); for(int i=0;i<md5data.Length-1;i++) { builder.Append(md5data[i].ToString("X2")); } return builder; }
我们也可以用Foreach进行循环
public string GetMD5String(string code) { //在登录的时候调用的 MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider(); //将字符串 转换 byte[] byte[] bytes = Encoding.Default.GetBytes(code); byte[] md5Byte = puteHash(bytes); //byte[] 转换 字符串 StringBuilder sb = new StringBuilder(); foreach (byte item in md5Byte) { sb.Append(item.ToString("X2")); }
sqlitecipher 例子

SQLiteCipher是一个用于在SQLite数据库中实现加密的库。
以下是一个使用SQLiteCipher在Android中创建和操作加密数据库的基本例子:首先,你需要在你的项目中添加SQLiteCipher库。
你可以通过Gradle依赖来添加:
groovy代码:
然后,你可以创建一个扩展了SupportSQLiteOpenHelper的类,如下所示:
java代码:
在这个例子中,我们创建了一个名为EncryptedDatabaseHelper的类,它扩展了DatabaseHelper。
我们在构造函数中指定了数据库的名称、密码以及在数据库打开时执行的关键配置。
在onCreate方法中,我们定义了要创建的表结构。
在onUpgrade方法中,我们定义了当数据库版本更新时需要执行的操作。
然后,你可以在你的应用中使用这个EncryptedDatabaseHelper来访问和操作加密的SQLite数据库:
java代码:
请注意,这只是一个基本的例子,实际使用时你可能需要根据你的应用需求进行适当的修改和扩展。
同时,确保你正确处理了可能抛出的异常,并在不再需要数据库连接时关闭它。
MD5加密

MD5加密易懂易用的MD5加密(可直接运行)概述:出于安全考虑,网络的传输中经常对传输数据做加密和编码处理,其中涉及以下几种:1、md5加密,该加密算法是单向加密,即加密的数据不能再通过解密还原。
相关类包含在java.security.MessageDigest包中。
2、3-DES加密,该加密算法是可逆的,解密方可以通过与加密方约定的密钥匙进行解密。
相关类包含在javax.crypto.*包中。
3、base64编码,是用于传输8bit字节代码最常用的编码方式。
相关类在sun.misc.BASE64Decoder 和sun.misc.BASE64Encoder 中。
4、URLEncoder编码,是一种字符编码,保证被传送的参数由遵循规范的文本组成。
相关类在.URLEncoder包中。
细节:1、进行MD5加密,得到byte[]/*** 进行MD5加密* @param String 原始的SPKEY* @return byte[] 指定加密方式为md5后的byte[]*/private byte[] md5(String strSrc){byte[] returnByte = null;try{MessageDigest md5 = MessageDigest.getInstance("MD5");returnByte = md5.digest(strSrc.getBytes("GBK"));}catch(Exception e){e.printStackTrace();}return returnByte;}2、得到3-DES的密钥匙/*** 得到3-DES的密钥匙* 根据根据需要,如密钥匙为24个字节,md5加密出来的是16个字节,因此后面补8个字节的0* @param String 原始的SPKEY* @return byte[] 指定加密方式为md5后的byte[]*/private byte[] getEnKey(String spKey){byte[] desKey=null;try{byte[] desKey1 = md5(spKey);desKey = new byte[24];int i = 0;while (i < desKey1.length && i < 24) { desKey[i] = desKey1[i];i++;}if (i < 24) {desKey[i] = 0;i++;}}catch(Exception e){e.printStackTrace();}return desKey;}3、3-DES加密/*** 3-DES加密* @param byte[] src 要进行3-DES加密的byte[] * @param byte[] enKey 3-DES加密密钥* @return byte[] 3-DES加密后的byte[]*/public byte[] Encrypt(byte[] src,byte[] enKey) {byte[] encryptedData = null;try{DESedeKeySpec dks = new DESedeKeySpec(enKey);SecretKeyFactory keyFactory = SecretKeyFactory.getInstanc e("DESede");SecretKey key = keyFactory.generateSecret(dks);Cipher cipher = Cipher.getInstance("DESede");cipher.init(Cipher.ENCRYPT_MODE, key);encryptedData = cipher.doFinal(src);}catch(Exception e){e.printStackTrace();}return encryptedData;}4、对字符串进行Base64编码/*** 对字符串进行Base64编码* @param byte[] src 要进行编码的字符** @return String 进行编码后的字符串*/public String getBase64Encode(byte[] src){String requestValue="";try{BASE64Encoder base64en = new BASE64Encoder();requestValue=base64en.encode(src);//System.out.println(requestValue);}catch(Exception e){e.printStackTrace();}return requestValue;}5、根据需要可以去掉字符串的换行符号/*** 去掉字符串的换行符号* base64编码3-DES的数据时,得到的字符串有换行符号,根据需要可以去掉*/private String filter(String str){String output = null;StringBuffer sb = new StringBuffer();for(int i = 0; i < str.length(); i++){int asc = str.charAt(i);if(asc != 10 && asc != 13)sb.append(str.subSequence(i, i + 1));}output = new String(sb);return output;}6、对字符串进行URLDecoder.encode(strEncoding)编码/*** 对字符串进行URLDecoder.encode(strEncoding)编码* @param String src 要进行编码的字符串** @return String 进行编码后的字符串*/public String getURLEncode(String src){String requestValue="";try{requestValue = URLEncoder.encode(src);}catch(Exception e){e.printStackTrace();}return requestValue;}7、对字符串进行URLDecoder.decode(strEncoding)解码/*** 对字符串进行URLDecoder.decode(strEncoding)解码* @param String src 要进行解码的字符串** @return String 进行解码后的字符串*/public String getURLDecoderdecode(String src) {String requestValue="";try{requestValue = URLDecoder.decode(src);}catch(Exception e){e.printStackTrace();}return requestValue;}8、进行3-DES解密(密钥匙等同于加密的密钥匙)/****进行3-DES解密(密钥匙等同于加密的密钥匙)。
android sdk加密原理
android sdk加密原理
AndroidSDK加密原理是指在Android应用程序开发中,如何采
用加密算法来保护应用程序的安全性和保密性。
加密算法可以实现数据的加密、认证、防篡改等功能,从而保护用户个人隐私和敏感数据。
在Android SDK中,常用的加密算法包括AES、RSA、MD5、SHA等。
其中,AES是对称加密算法,它采用相同的密钥对数据进行加密和解密。
RSA是非对称加密算法,它采用公钥和私钥对数据进行加密和解密。
MD5和SHA是哈希算法,它们可以将任意长度的数据映射成固定长度的摘要,从而实现数据的唯一性验证和完整性校验。
在Android应用程序开发中,通常使用加密算法对用户登录信息、密码、支付信息等敏感数据进行加密,防止黑客攻击和窃取用户信息。
同时,也可以利用加密算法对应用程序进行数字签名和证书认证,确保应用程序的真实性和安全性。
总之,Android SDK加密原理是非常重要的安全保障措施,开发者需要熟练掌握各种加密算法的使用方法和技巧,从而保护用户的隐私和数据安全。
- 1 -。
MD5加密算法原理
MD5加密算法原理MD5(Message-Digest Algorithm 5)是一种常见的哈希加密算法,广泛应用于数据完整性和密码保护方面。
它是由著名的RSA数据安全公司的雇员罗纳德·李维斯特(Ronald Rivest)于1991年设计的。
MD5算法的原理是将任意长度的输入数据转换为固定长度的输出(128位),这个输出称为哈希值。
通过MD5算法,对同一输入得到的哈希值是唯一的,不同的输入得到不同的哈希值。
MD5算法的具体步骤如下:1.填充数据:根据MD5算法的规定,输入的数据需要进行填充。
填充的方式是在数据的末尾添加一个1,然后添加若干个0,直到数据的长度满足要求。
2.附加长度:将数据的原始长度(以64位二进制表示)附加到数据的末尾。
3.初始化缓冲区:创建一个128位的缓冲区,用于存储中间结果。
4.划分数据:将填充和附加长度之后的数据划分为若干个512位的分组。
5.处理分组:对每个分组进行处理。
处理的流程包括四个连续的步骤:初始化状态(将缓冲区的初始值复制到状态中),处理分组(通过一系列运算对分组进行处理),更新状态(将当前状态与处理结果合并得到新的状态),输出结果(将最后的状态转化为128位的哈希值)。
6.输出结果:将最后的128位哈希值输出。
MD5算法的核心是四个函数,分别用于不同的数据处理步骤:1.F函数:F函数是一个基本的逻辑运算,将B、C、D三个输入进行位异或、与、或的组合,得到一个32位的结果。
2.G函数:G函数与F函数类似,将C、D、A三个输入进行位异或、与、或的组合,得到一个32位的结果。
3.H函数:H函数将B、C、D三个输入进行位异或、与、非的组合,得到一个32位的结果。
4.I函数:I函数将C、B的非、A进行位异或、与的组合,得到一个32位的结果。
这四个函数在处理不同的分组时会依次循环使用,通过循环计算和更新状态来实现数据的加密。
MD5算法具有以下特点:1.哈希值唯一性:通过MD5算法得到的哈希值是唯一的,不同的输入得到不同的哈希值。
SQLite的加密扩展方法
SQLite的加密扩展方法这篇文章专门介绍如何扩展当前正越来越流行SQLite的数据库的加密部分, SQLite是"一个无须任何配置部署的嵌入式SQL数据库."背景我为什么要写这个扩展? 为了满足我自己的一些疯狂的想法. :) 好了,不开玩笑了. 不久前我想写一个程序用来存储一些私人信息 (我自己的一个项目). 我不想用那些很大的开源数据库,例如MySQL,因为它们确实是太大了,需要占用很大的空间,而且要单独的安装部署. 后来我发现了 SQLite, 它非常的小巧而且运行起来很快,并且它的API函数十分的简单,在我的C++程序当中可以很方便的使用. 就是有一个问题,大概是由于它要保持简单所以它不支持任何的验证和加密. 这令我一点安全感都没有.因此我开始寻找SQLite的加密解决方案. 我找到了两个,但是它们都是商业软件. SQLite的作者, D. Richard Hipp先生提供了一个可以对数据库文件进行完全加密SQLite的加强版本. 也就是那个叫做SQLcrypt(tm)的商业软件, 它实现了数据存储层的透明加密. 不幸的是它们对于我们这些普通人来说都太贵了, 尤其是对于我这种非商业目的只是想用SQLite开发一些小应用自己玩的人来说更是如此. 然而我却是非常的需要对数据库进行加密- 在数据库层对整个数据库文件进行透明的加密. 所有的开发者和用户只需要在打开数据库的时候提供密码就可以了. 然后接下来的事情就全都交给数据库去做了. 这种方式将比那种在数据和字段上的加密要容易的多,也方便的多, 不然需要加密的字段就都要设计成BLOB或者string类型了.在我搜索了SQLite的邮件列表和在Google上搜索免费的SQLite插件或扩展之后,我发现没有能够满足我的需求的, 所以我决定自己写一个. 我从SQLite的作者预留的一些用来支持数据库加密解密的API接口获得了灵感,并且我发现实际上也有人写了一个基于SQLite的加密库 (SQLcrypt). 我花费了几天的时间来研究一些加密的算法,我要选出一种使用(The AES (Rijndael) block cipher) ,另外还有就是如何生成密码, 当然最重要的就是我怎样才能把我用来完成加密解密数据库的代码嵌入SQLite的核心当中执行.扩展模块的技术说明书这个扩展模块的结构相当的简单. 大体上来说我编写了SQLite代码中已经提供了原型的四个函数: sqlite3_key(), sqlite3_rekey(),sqlite3CodecGetKey(), 和 sqlite3CodecAttach(). 前两个函数是在sqlite3.h头文件中定义的公共API. 另外两个定义在 attach.c 的sqlite3Attach()函数中. 我阅读了它的源代码中提供的函数原形(主要是pager.c 和 btree.c两个文件),看一下它们是如何工作的. 我发现实现他们并不困难,因为对数据库加密解密的机制已经都实现了(感谢 Richard!).这个扩展的其他部分就是写一个用来加密和解密的程序. 为此我使用了AES加密算法,其中代码的关键部分取自Brian Gladman (his site) 还有David Ireland的高精度加密算法库BigDigits. 因为我不想在一开始的时候就跟SQLite的数据库格式过多的纠缠, 所以我用了计数器模式(CTR)把AES加密块转换成256字节的加密流. 这样加密之后的密文就可以和原来的明文有相同的长度,加密和没加密的数据库文件尺寸相同 (也就是说不需要保存而外的信息). 我还使用了Brian Gladman网站上提供的 PKCS#5签名的SHA256算法从用户提供的密码中来生成AES 算法的密钥. 如果是这样的话, 我就要写很多的代码来处理salt value 才能避免往数据库中存入额外的信息.Pager结构体用来存放指向编码函数的指针, 用来从数据库中加密或解密数据. 我写了这些代码用来加密或解密数据库中的记录. 因为我使用了计数器(CTR)模式,加密和解密用的是相同的算法,所以简单了许多. 但是我还是需要初始化一个进程的计数器. 我把数据库切分成了一个一个的块,每个都作为一个单独的AES加密块 (例如默认的情况下是16字节). 每个块都从0开始编号. 依据传入编码函数的page size和page number参数, 我算出计数块内的计数值(等于块的编号) 和偏移量 (具体实现请看代码),然后用它来初始化加密流.安装和使用警告: 目前的代码还在试验当中. 因此我很希望大家来帮我测试这些代码(因为我没有那么多的时间和数据去进行测试), 使用的风险需要你自己去承担.如果要使用这个扩展模块你需要下载修改过的SQLite和BigDigits库,然后自己编译它们. 我只是在Win32系统下用MinGW compiler编译并测试过. 但是我认为它在*nix系统下也能正常工作. 如果你要使用MinGW, 你需要下载最新版MinGW的和M-sys . 我是用gcc 3.4.2编译的.BigDigits高精度算法库可以从这里下载, 我自己写了一个Makefile 文件用MinGW把它编译成了一个静态的库文件. 下载包里有编译好的BigDigits库文件. (bigdigits.h 和libbdmpa.a) 如果你想要自己编译,请遵循以下步骤:1. 从上面的地址下载源代码.2. 解压到一个目录里.3. 下载并保存'Makelib.mak'文件到刚才的目录.4. 修改头文件中最开始的一些 #define's和typedef's使之适合你的操作系统.5. 在命令行中输入'make -f Makelib.mak'编译源代码.6. 把编译出来的libbdmpa.a文件和bigdigits.h头文件拷贝到SQLite的顶层目录下.对于Linux/Unix和MinGW的用户, 你只需要按照通常的步骤去做就可以./configuremakemake install把SQLiteSecure编译了(包括配置和安装). 编译出来的库文件和命令行可执行文件和原始的SQLite基本相同,除了前面加上了'sec'前缀,从而避免和你之前使用的SQLite命名冲突.注意: **请** 不要问我如何用VC++或者其他编译其编译源代码. 以为我不用,所以不知道.你可以用的命令行sqlite3sec工具来先体验一下SQLiteSecure. 打开一个普通的数据库文件, 输入$ sqlite3sec a.db打开一个加密的数据库文件, 输入$ sqlite3sec -key "your passphrase" b.db在sqlite3sec中你可以使用下列三种方法来添加一个加密的数据库:sqlite> ATTACH 'b.db' AS b;sqlite> ATTACH 'b.db' AS b KEY 'your passphrase';sqlite> ATTACH 'b.db' AS b KEY blob;第一种方法使用和主数据库相同的密码(或者是没有密码) , 第二种方法用你输入的短语来做密码. 第三种方法假设你用BLOB的十六进制值作为密码(例如 f03d69ac3981...). 不过我还没有充分的测试这个使用BLOB作为密码的版本. 请注意:如果你的主数据库是加密的,然后你想添加一个不加密的数据库,这种情况下你需要用第二种方法然后传递一个空字符串('')作为密码.在sqlite3sec中你还可以用.rekey命令来改变数据库的密码,但是这个我目前还没有写完,如果调用的话会返回一个错误. ;)API方法, 如果你需要加密一个数据库,你仅仅需要从用户或者其他的地方得到设置的密码, 然后在sqlite3_open() 或者 sqlite3_open16()函数之后,在调用其他的sqlite3函数之前调用sqlite3_key()函数。
MD5加密算法原理及实现
MD5加密算法原理及实现MD5消息摘要算法,属Hash算法⼀类。
MD5算法对输⼊任意长度的消息进⾏运⾏,产⽣⼀个128位的消息摘要。
以下所描述的消息长度、填充数据都以位(Bit)为单位,字节序为⼩端字节。
算法原理1、数据填充对消息进⾏数据填充,使消息的长度对512取模得448,设消息长度为X,即满⾜X mod 512=448。
根据此公式得出需要填充的数据长度。
填充⽅法:在消息后⾯进⾏填充,填充第⼀位为1,其余为0。
2、添加消息长度在第⼀步结果之后再填充上原消息的长度,可⽤来进⾏的存储长度为64位。
如果消息长度⼤于264,则只使⽤其低64位的值,即(消息长度对 264取模)。
在此步骤进⾏完毕后,最终消息长度就是512的整数倍。
3、数据处理准备需要⽤到的数据:4个常数:A = 0x67452301, B = 0x0EFCDAB89, C = 0x98BADCFE, D = 0x10325476;4个函数:F(X,Y,Z)=(X & Y) | ((~X) & Z); G(X,Y,Z)=(X & Z) | (Y & (~Z)); H(X,Y,Z)=X ^ Y ^ Z; I(X,Y,Z)=Y ^ (X | (~Z));把消息分以512位为⼀分组进⾏处理,每⼀个分组进⾏4轮变换,以上⾯所说4个常数为起始变量进⾏计算,重新输出4个变量,以这4个变量再进⾏下⼀分组的运算,如果已经是最后⼀个分组,则这4个变量为最后的结果,即MD5值。
具体计算的实现较为复杂,建议查阅相关书籍,下⾯给出在C++上的实现代码。
代码实现#MD5.h1 #ifndef MD5H2#define MD5H3 #include <math.h>4 #include <Windows.h>56void ROL(unsigned int &s, unsigned short cx); //32位数循环左移实现函数7void ltob(unsigned int &i); //B\L互转,接受UINT类型8 unsigned int* MD5(const char* mStr); //接⼝函数,并执⾏数据填充,计算MD5时调⽤此函数910#endif#MD5.cpp1 #include "MD5.h"23/*4组计算函数*/4 inline unsigned int F(unsigned int X, unsigned int Y, unsigned int Z)5 {6return (X & Y) | ((~X) & Z);7 }8 inline unsigned int G(unsigned int X, unsigned int Y, unsigned int Z)9 {10return (X & Z) | (Y & (~Z));11 }12 inline unsigned int H(unsigned int X, unsigned int Y, unsigned int Z)13 {14return X ^ Y ^ Z;15 }16 inline unsigned int I(unsigned int X, unsigned int Y, unsigned int Z)17 {18return Y ^ (X | (~Z));19 }20/*4组计算函数结束*/2122/*32位数循环左移实现函数*/23void ROL(unsigned int &s, unsigned short cx)24 {25if (cx > 32)cx %= 32;26 s = (s << cx) | (s >> (32 - cx));27return;28 }2930/*B\L互转,接收UINT类型*/31void ltob(unsigned int &i)32 {33 unsigned int tmp = i;//保存副本34byte *psour = (byte*)&tmp, *pdes = (byte*)&i;35 pdes += 3;//调整指针,准备左右调转36for (short i = 3; i >= 0; --i)37 {38 CopyMemory(pdes - i, psour + i, 1);39 }40return;41 }4243/*44MD5循环计算函数,label=第⼏轮循环(1<=label<=4),lGroup数组=4个种⼦副本,M=数据(16组32位数指针)45种⼦数组排列⽅式: --A--D--C--B--,即 lGroup[0]=A; lGroup[1]=D; lGroup[2]=C; lGroup[3]=B;46*/47void AccLoop(unsigned short label, unsigned int *lGroup, void *M)48 {49 unsigned int *i1, *i2, *i3, *i4, TAcc, tmpi = 0; //定义:4个指针; T表累加器;局部变量50 typedef unsigned int(*clac)(unsigned int X, unsigned int Y, unsigned int Z); //定义函数类型51const unsigned int rolarray[4][4] = {52 { 7, 12, 17, 22 },53 { 5, 9, 14, 20 },54 { 4, 11, 16, 23 },55 { 6, 10, 15, 21 }56 };//循环左移-位数表57const unsigned short mN[4][16] = {58 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },59 { 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 },60 { 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 },61 { 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 }62 };//数据坐标表63const unsigned int *pM = static_cast<unsigned int*>(M);//转换类型为32位的Uint64 TAcc = ((label - 1) * 16) + 1; //根据第⼏轮循环初始化T表累加器65 clac clacArr[4] = { F, G, H, I }; //定义并初始化计算函数指针数组6667/*⼀轮循环开始(16组->16次)*/68for (short i = 0; i < 16; ++i)69 {70/*进⾏指针⾃变换*/71 i1 = lGroup + ((0 + i) % 4);72 i2 = lGroup + ((3 + i) % 4);73 i3 = lGroup + ((2 + i) % 4);74 i4 = lGroup + ((1 + i) % 4);7576/*第⼀步计算开始: A+F(B,C,D)+M[i]+T[i+1] 注:第⼀步中直接计算T表*/77 tmpi = (*i1 + clacArr[label - 1](*i2, *i3, *i4) + pM[(mN[label - 1][i])] + (unsigned int)(0x100000000UL * abs(sin((double)(TAcc + i)))));78 ROL(tmpi, rolarray[label - 1][i % 4]);//第⼆步:循环左移79 *i1 = *i2 + tmpi;//第三步:相加并赋值到种⼦80 }81return;82 }8384/*接⼝函数,并执⾏数据填充*/85 unsigned int* MD5(const char* mStr)86 {87 unsigned int mLen = strlen(mStr); //计算字符串长度88if (mLen < 0) return0;89 unsigned int FillSize = 448 - ((mLen * 8) % 512); //计算需填充的bit数90 unsigned int FSbyte = FillSize / 8; //以字节表⽰的填充数91 unsigned int BuffLen = mLen + 8 + FSbyte; //缓冲区长度或者说填充后的长度92 unsigned char *md5Buff = new unsigned char[BuffLen]; //分配缓冲区93 CopyMemory(md5Buff, mStr, mLen); //复制字符串到缓冲区9495/*数据填充开始*/96 md5Buff[mLen] = 0x80; //第⼀个bit填充197 ZeroMemory(&md5Buff[mLen + 1], FSbyte - 1); //其它bit填充0,另⼀可⽤函数为FillMemory98 unsigned long long lenBit = mLen * 8ULL; //计算字符串长度,准备填充99 CopyMemory(&md5Buff[mLen + FSbyte], &lenBit, 8); //填充长度100/*数据填充结束*/101102/*运算开始*/103 unsigned int LoopNumber = BuffLen / 64; //以16个字为⼀分组,计算分组数量104 unsigned int A = 0x67452301, B = 0x0EFCDAB89, C = 0x98BADCFE, D = 0x10325476;//初始4个种⼦,⼩端类型105 unsigned int *lGroup = new unsigned int[4]{ A, D, C, B}; //种⼦副本数组,并作为返回值返回106for (unsigned int Bcount = 0; Bcount < LoopNumber; ++Bcount) //分组⼤循环开始107 {108/*进⼊4次计算的⼩循环*/109for (unsigned short Lcount = 0; Lcount < 4;)110 {111 AccLoop(++Lcount, lGroup, &md5Buff[Bcount * 64]);112 }113/*数据相加作为下⼀轮的种⼦或者最终输出*/114 A = (lGroup[0] += A);115 B = (lGroup[3] += B);116 C = (lGroup[2] += C);117 D = (lGroup[1] += D);118 }119/*转换内存中的布局后才能正常显⽰*/120 ltob(lGroup[0]);121 ltob(lGroup[1]);122 ltob(lGroup[2]);123 ltob(lGroup[3]);124 delete[] md5Buff; //清除内存并返回125return lGroup;126 }再给出调⽤实例(以win32控制台应⽤程序为例):#main.cpp1 #include <iostream>2 #include <string.h>3 #include <stdlib.h>4 #include "MD5.h"56int main(int argc, char **argv)7 {8char tmpstr[256], buf[4][10];9 std::cout << "请输⼊要加密的字符串:";10 std::cin >> tmpstr;11 unsigned int* tmpGroup = MD5(tmpstr);12 sprintf_s(buf[0], "%8X", tmpGroup[0]);13 sprintf_s(buf[1], "%8X", tmpGroup[3]);14 sprintf_s(buf[2], "%8X", tmpGroup[2]);15 sprintf_s(buf[3], "%8X", tmpGroup[1]);16 std::cout <<"MD5:"<< buf[0] << buf[1] << buf[2] << buf[3] << std::endl; 1718 delete[] tmpGroup;19return0; //在此下断点才能看到输出的值20 }注:以上代码在VS2013上编译通过。