文档章节

PHP、JAVA、C#、Object-C 通用的DES加密

J
 JACKFEI
发布于 2016/10/24 08:56
字数 1634
阅读 13
收藏 0

EncryptUtil

feiyangklDES

一行代码完成DES加密,加密模式 DES + CBC githubDemo:https://github.com/feiyangkl/EncryptUtil

DEMO GIF

Untitled.gif

DEMO 简介

最近项目中用到DES加密,在这里整理成篇,供大家参考阅读,在使用该demo过程中,你可能会遇到一些问题,首先你需要看一下下面的demo简介,看看该demo 是否适合你的项目。

项目中的DES加解密主要用在网络请求过程中对上传的参数进行加密,对从后台服务器获取的数据进行解密。

整体的加密流程为:

加密的过程: 参数字典 --> json字符串 --> base64加密后的字符串 --> DES加密后base64再加密 --> 输出最终加密后的字符串;

解密的过程: 

后台服务器获取加密的字符串 -->base64解密 --> DES解密后base64解密 --> json字符串 --> 数据字典;(与加密的过程相反)

网上对DES的详细介绍已经有很多,在这里不做赘述,如果你需要了解这些知识,google.
我们公司后台为JAVA,移动端有iOS与Android, 讨论后选择DES的加密模式为 DES + CBC (注意是否满足你的加密需求)。

为什么选择这种加密模式:

如果采用PKCS7Padding或者PKCS5Padding这种加密方式,末端添加的数据可能不固定,在解码后需要把末端多余的字符去掉,比较棘手。

如果不管补齐多少位,末端都是'\0',去掉的话比较容易操作。 最主要的是能使得

iOS/Android/PHP相互通信,也是加密过程中最难搞的地方,尤其需要开发者注意。

项目中用到了 google 的 base64 加解密库 GTMBase64,但是这个库已经有很多年没有更新 还是 MRC 开发模式,需要手动配置一下:

1.选择项目中的Targets,选中你所要操作的Target,

2.选Build Phases,在其中Complie Sources中选择需要ARC的文件双击,并在输入框中输入 -fno-objc-arc

DEMO 使用示例

//加密

/// 加密
NSMutableDictionary *dic=[NSMutableDictionary dictionary];
[dic setValue:@"111111" forKey:@"password"];
[dic setValue:@"admin" forKey:@"userName"];

/*
加密{"userName":"admin","password":"111111"}和
{
"userName" : "admin",
"password" : "111111"
}
加密后结果是不一样的,一定要确定公司后台是怎么加密的,要不然有可能会错误
*/
NSString *jsonstr = [dic JSONString];
self.lb_show.text = [EncryptUtil encryptUseDES:jsonstr key:gkey];

//加密结果 iMXucxT4Z6v0ZILRJtUX1W/8KfR1wvqqdDxHiOdfTvkdVQQnJ7p1DdMPQXM60BwNHBdjhTqbnXIN
eEYVIHbb6w==

//解密

- (IBAction)clickDecodeBtn:(UIButton *)sender {

//上面加密的结果
NSString *AESString = @"iMXucxT4Z6v0ZILRJtUX1W/8KfR1wvqqdDxHiOdfTvkdVQQnJ7p1DdMPQXM60BwNHBdjhTqbnXIN
eEYVIHbb6w==";

///解密
self.lb_show.text = [EncryptUtil decryptUseDES:self.lb_show.text key:gkey];

解密结果:{"userName":"admin","password":"111111"}

}
java 
/**
* <li>
* 方法名称:encrypt</li> <li>
* 加密方法
* @param xmlStr
*            需要加密的消息字符串
* @return 加密后的字符串
*/
public static String encrypt(String xmlStr) {
byte[] encrypt = null;

try {
// 取需要加密内容的utf-8编码。
encrypt = xmlStr.getBytes("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 取MD5Hash码,并组合加密数组
byte[] md5Hasn = null;
try {

//            md5Hash = EncryptUtil.MD5Hash(temp, 16, temp.length - 16);

md5Hasn = EncryptUtil.MD5Hash(encrypt, 0, encrypt.length);
} catch (Exception e) {
e.printStackTrace();
}
// 组合消息体
byte[] totalByte = EncryptUtil.addMD5(md5Hasn, encrypt);

// 取密钥和偏转向量
byte[] key = new byte[8];
byte[] iv = new byte[8];
getKeyIV(EncryptUtil.key, key, iv);

SecretKeySpec deskey = new SecretKeySpec(key, "DES");

IvParameterSpec ivParam = new IvParameterSpec(iv);

// 使用DES算法使用加密消息体
byte[] temp = null;
try {
temp = EncryptUtil.DES_CBC_Encrypt(totalByte, deskey, ivParam);
} catch (Exception e) {
e.printStackTrace();
}

// 使用Base64加密后返回
return new BASE64Encoder().encode(temp);
}

ios
/// 加密方法
+ (NSString *) encryptUseDES:(NSString *)plainText key:(NSString *)key
{
/// 转换成data
NSData* plainTextdata = [plainText dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger plainTextdatLength = [plainTextdata length];
/// 将data数据MD5加密
unsigned char digest[16];
CC_MD5([plainTextdata bytes],(CC_LONG) plainTextdatLength, digest);

// 总长度 MD5 + plainText
NSUInteger plainTextBufferTotalSize  = 16 +plainTextdatLength;

// 将plainText 转换成bytes
Byte *testByte = (Byte *)[plainTextdata bytes];

// 定义totalByte
Byte totalByte[plainTextBufferTotalSize];

for (int i = 0; i < plainTextBufferTotalSize; ++i) {
if (i<16) {
totalByte[i] =digest[i];
}else{
totalByte[i] =testByte[i - 16];
}
}

/// 将key base64 编码
NSData *baseKey = [GTMBase64 decodeString:key];
Byte *buf = (Byte *)[baseKey bytes];

Byte key1[8];
Byte iv2[8];
for (int i = 0; i < 8; i++) {

key1[i] = buf[i];
}
//    // 后8位为iv向量
for (int i = 0; i < 8 ; i++) {
iv2[i] = buf[i + 8];
}

NSString *ciphertext = nil;
unsigned char buffer[1024];
memset(buffer, 0, sizeof(char));
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding,
key1,
kCCKeySizeDES,
iv2,
totalByte,
plainTextBufferTotalSize,
buffer,
1024,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {

NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
ciphertext = [[NSString alloc] initWithData:[GTMBase64 encodeData:data] encoding:NSUTF8StringEncoding];
}
return ciphertext;
}


java 解密
/**
* <li>
* 方法名称:encrypt</li> <li>
* 功能描述:
*
* <pre>
* 解密方法
* </pre>
*
* </li>
*
* @param xmlStr
*            需要解密的消息字符串
* @return 解密后的字符串
* @throws Exception
*/
public static String decrypt(String xmlStr) throws Exception {
// base64解码
BASE64Decoder decoder = new BASE64Decoder();
byte[] encBuf = null;
try {
encBuf = decoder.decodeBuffer(xmlStr);
} catch (IOException e) {
e.printStackTrace();
}

// 取密钥和偏转向量
byte[] key = new byte[8];
byte[] iv = new byte[8];
getKeyIV(EncryptUtil.key, key, iv);

SecretKeySpec deskey = new SecretKeySpec(key, "DES");
IvParameterSpec ivParam = new IvParameterSpec(iv);

// 使用DES算法解密
byte[] temp = null;
try {
temp = EncryptUtil.DES_CBC_Decrypt(encBuf, deskey, ivParam);
} catch (Exception e) {
e.printStackTrace();
}

// 进行解密后的md5Hash校验
byte[] md5Hash = null;
try {
md5Hash = EncryptUtil.MD5Hash(temp, 16, temp.length - 16);
} catch (Exception e) {
e.printStackTrace();
}

// 进行解密校检
for (int i = 0; i < md5Hash.length; i++) {
if (md5Hash[i] != temp[i]) {
// System.out.println(md5Hash[i] + "MD5校验错误。" + temp[i]);
throw new Exception("MD5校验错误。");
}
}

// 返回解密后的数组,其中前16位MD5Hash码要除去。
return new String(temp, 16, temp.length - 16, "utf-8");
}

ios 解密

/// 解密方法
+ (NSString *) decryptUseDES:(NSString *)plainText key:(NSString *)key {

// plainTextData转换 base64
NSData *BasePlainTextData = [GTMBase64 decodeString:plainText];
// 将BasePlainTextDatabase64转换为byte数组
Byte *BasePlainTextDataByte = (Byte *)[BasePlainTextData bytes];

// 将key base64解码
NSData *baseKey = [GTMBase64 decodeString:key];
// 将key 转换成 byte数组
Byte *buf = (Byte *)[baseKey bytes];

// 定义key iv byte数组
Byte keyByte[8];
Byte ivByte[8];
for (int i = 0; i < 8; i++) {
keyByte[i] = buf[i];
}
//    // 后8位为iv向量
for (int i = 0; i < 8 ; i++) {
ivByte[i] = buf[i + 8];
}

/// 返回值长度
size_t bufferSize = BasePlainTextData.length;

// 字符串长度比较长 返回值给大点
unsigned char buffer[1024];
memset(buffer,0,sizeof(char));
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding,
keyByte,
kCCKeySizeDES,
ivByte,
BasePlainTextDataByte,
bufferSize,
buffer,
1024,
&numBytesEncrypted);

NSData *resultdata;
if (cryptStatus == kCCSuccess) {

resultdata = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
}

Byte *resultByte = (Byte *)[resultdata bytes];

// 返回数组长度 减去MD5加密的16
size_t returnLength = resultdata.length - 16;
/// 定义
Byte decryptionByte[returnLength];

for (int i = 0; i < returnLength; ++i) {
decryptionByte[i] = resultByte[i+16];
}

/// md5 校验
//    unsigned char digest[16];
//    CC_MD5(decryptionByte,returnLength, digest);
//    NSData *md5data = [NSData dataWithBytes:digest length:16];

// 进行解密校检
//    Byte *md5bte= (Byte *)[md5data bytes];

//    for (int i = 0; i < 40; i++) {
//
//
//        if (md5bte[i] !=decryptionByte[i] ) {
//            // System.out.println(md5Hash[i] + "MD5校验错误。" + temp[i]);
//            //            throw new Exception("MD5校验错误。");
//
//            NSLog(@"c1111uowu");
//        }else{
//            NSLog(@"cuowu");
//        }
//    }

NSData *namedata = [[NSData alloc] initWithBytes:decryptionByte length:returnLength];

NSString *str = [[NSString alloc] initWithData:namedata encoding:NSUTF8StringEncoding];
NSLog(@"%@",str);

return str;

}

项目中遇到的一些坑,在 DEMO 中都已经注释出来,写的比较清楚,如果该 DEMO 帮助了您,也希望能给个 star

鼓励一下,如果在使用中您有任何问题,可以在 github issues,我会尽自己能力给您答复 。

在这里感谢这些 blog 的作者,让我在开发过程中少走了很多弯路:

[http://www.open-open.com/lib/view/open1452738808948.html)

[https://my.oschina.net/jsan/blog/54385)

[http://blog.csdn.net/j_akill/article/details/44079597][http://blog.csdn.net/j_akill/article/details/44079597)

[http://blog.csdn.net/jbjwpzyl3611421/article/details/18256917)

[https://github.com/IMCCP/CCPAESEncode/blob/master/CCPAESEncode)

© 著作权归作者所有

J
粉丝 0
博文 2
码字总数 2246
作品 0
朝阳
程序员
私信 提问

暂无文章

x002-语言元素

变量命令规则 硬性规则: 变量名由字母(广义的Unicode字符,不包括特殊字符)、数字和下划线构成,数字不能开头。 大小写敏感(大写的a和小写的A是两个不同的变量)。 不要跟关键字(有特殊...

伟大源于勇敢的开始
今天
4
0
nginx反向代理配置

nginx配置文件位置/usr/local/nginx/conf/nginx.conf 配置文件修改: # cd /usr/local/nginx/conf # vim nginx.conf server {listen 80;server_name localhost;#charset k......

行者终成事
今天
5
0
OSChina 周日乱弹 —— 这是假的,和我之前的不一样

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 小小编辑推荐:《男孩》-梁博 / 陶孟童 / 肖和东 / 高誉容 《男孩》-梁博 / 陶孟童 / 肖和东 / 高誉容 手机党少年们想听歌,请使劲儿戳(这里...

小小编辑
今天
8
0
Rust学习笔记一 数据类型

写在前面 我也不是什么特别厉害的大牛,学历也很低,只是对一些新语言比较感兴趣,接触过的语言不算多也不算少,大部分也都浅尝辄止,所以理解上可能会有一些偏差。 自学了Java、Kotlin、Python、...

MusiCodeXY
今天
5
0
Java 脚本引擎入门

Java Script Engine Java 脚本引擎可以将脚本嵌入Java代码中,可以自定义和扩展Java应用程序,自JDK1.6被引入,基于Rhino引擎,JDK1.8后使用Nashorn引擎,支持ECMAScript 5,但后期还可能会换...

阿提说说
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部