文档章节

Objective-C 和 Java 下 DES加解密保持一致的方式

山哥
 山哥
发布于 2012/04/19 19:21
字数 1476
阅读 2605
收藏 5
最近做了一个移动项目,是有服务器和客户端类型的项目,客户端是要登录才行的,登录的密码要用DES加密,服务器是用Java开发的,客户端要同时支持多平台(Android、iOS),在处理iOS的DES加密的时候遇到了一些问题,起初怎么调都调不成和Android端生成的密文相同。最终一个忽然的想法让我找到了问题的所在,现在将代码总结一下,以备自己以后查阅。

首先,Java端的DES加密的实现方式,代码如下:

public class DES {
	private static final byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 };
	 
	public static String encryptDES(String encryptString, String encryptKey) throws Exception 
	{
		IvParameterSpec zeroIv = new IvParameterSpec(iv);
		SecretKeySpec key = new SecretKeySpec(encryptKey.getBytes(), "DES");
		Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
		cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
		byte[] encryptedData = cipher.doFinal(encryptString.getBytes());
		return Base64.encode(encryptedData);
	}
}

上述代码用到了一个Base64的编码类,其代码的实现方式如下:

public class Base64 {
	 private static final char[] legalChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
	 
	 /**
	 * data[]进行编码
	 * 
	 * @param data
	 * @return
	 */
	 public static String encode(byte[] data) {
		 int start = 0;
		 int len = data.length;
		 StringBuffer buf = new StringBuffer(data.length * 3 / 2);
		 
		 int end = len - 3;
		 int i = start;
		 int n = 0;
		 
		 while (i <= end) {
			 int d = ((((int) data[i]) & 0x0ff) << 16) | ((((int) data[i + 1]) & 0x0ff) << 8) | (((int) data[i + 2]) & 0x0ff);
		 
			buf.append(legalChars[(d >> 18) & 63]);
			buf.append(legalChars[(d >> 12) & 63]);
			buf.append(legalChars[(d >> 6) & 63]);
			buf.append(legalChars[d & 63]);
			 
			i += 3;
			 
			if (n++ >= 14) {
				n = 0;
				buf.append(" ");
			}
		}
		 
		 if (i == start + len - 2) {
			 int d = ((((int) data[i]) & 0x0ff) << 16) | ((((int) data[i + 1]) & 255) << 8);
			 
			buf.append(legalChars[(d >> 18) & 63]);
			buf.append(legalChars[(d >> 12) & 63]);
			buf.append(legalChars[(d >> 6) & 63]);
			buf.append("=");
		} 
		else if (i == start + len - 1) {
			int d = (((int) data[i]) & 0x0ff) << 16;
			 
			buf.append(legalChars[(d >> 18) & 63]);
			buf.append(legalChars[(d >> 12) & 63]);
			buf.append("==");
		}
		 
		return buf.toString();
	}
}

以上便是Java端的DES加密方法的全部实现过程。

我还编写了一个将byte的二进制转换成16进制的方法,以便调试的时候使用打印输出加密后的byte数组的内容,这个方法不是加密的部分,只是为调试而使用的:

/**将二进制转换成16进制 
	* @param buf 
	* @return String
	*/ 
	public static String parseByte2HexStr(byte buf[]) 
	{ 
		StringBuffer sb = new StringBuffer(); 
		for (int i = 0; i < buf.length; i++) 
		{ 
			String hex = Integer.toHexString(buf[i] & 0xFF); 
			if (hex.length() == 1) { 
				hex = '0' + hex; 
			} 
			sb.append(hex.toUpperCase()); 
		} 
		return sb.toString(); 
	}

下面是Objective-c在iOS上实现的DES加密算法: 添加头文件#import

- (NSString *) encryptUseDES:(NSString *)plainText key:(NSString *)key
{
     NSString *ciphertext = nil;
     const char *textBytes = [plainText UTF8String];
    NSUInteger dataLength = [plainText length];
     unsigned char buffer[1024];
     memset(buffer, 0, sizeof(char));
     size_t numBytesEncrypted = 0;
     CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
                                              kCCOptionPKCS7Padding,
                                              [key UTF8String], kCCKeySizeDES,
                                              iv,
                                              textBytes, dataLength,
                                              buffer, 1024,
                                              &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
         NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
 
         ciphertext = [data base64Encoding];
         }
     return ciphertext;
}

下面是一个关键的类:NSData的Category实现,关于Category的实现网上很多说明不再讲述。

static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 - (NSString *)base64Encoding;
 {
 if (self.length == 0)
 return @"";
 
 char *characters = malloc(self.length*3/2);
 
 if (characters == NULL)
 return @"";
 
 int end = self.length - 3;
 int index = 0;
 int charCount = 0;
 int n = 0;
 
 while (index <= end) {
 int d = (((int)(((char *)[self bytes])[index]) & 0x0ff) << 16) 
 | (((int)(((char *)[self bytes])[index + 1]) & 0x0ff) << 8)
 | ((int)(((char *)[self bytes])[index + 2]) & 0x0ff);
 
 characters[charCount++] = encodingTable[(d >> 18) & 63];
 characters[charCount++] = encodingTable[(d >> 12) & 63];
 characters[charCount++] = encodingTable[(d >> 6) & 63];
 characters[charCount++] = encodingTable[d & 63];
 
 index += 3;
 
 if(n++ >= 14)
 {
 n = 0;
 characters[charCount++] = ' ';
 }
 }
 
 if(index == self.length - 2)
 {
 int d = (((int)(((char *)[self bytes])[index]) & 0x0ff) << 16) 
 | (((int)(((char *)[self bytes])[index + 1]) & 255) << 8);
 characters[charCount++] = encodingTable[(d >> 18) & 63];
 characters[charCount++] = encodingTable[(d >> 12) & 63];
 characters[charCount++] = encodingTable[(d >> 6) & 63];
 characters[charCount++] = '=';
 }
 else if(index == self.length - 1)
 {
 int d = ((int)(((char *)[self bytes])[index]) & 0x0ff) << 16;
 characters[charCount++] = encodingTable[(d >> 18) & 63];
 characters[charCount++] = encodingTable[(d >> 12) & 63];
 characters[charCount++] = '=';
 characters[charCount++] = '=';
 }
 NSString * rtnStr = [[NSString alloc] initWithBytesNoCopy:characters length:charCount encoding:NSUTF8StringEncoding freeWhenDone:YES];
return rtnStr;
 }

这个方法和java端的那个Base64的encode方法基本上是一个算法,只是根据语言的特点不同有少许的改动。

下面也是Objective-c的一个二进制转换为16进制的方法,也是为了测试方便查看写的:

+(NSString *) parseByte2HexString:(Byte *) bytes
 {
 NSMutableString *hexStr = [[NSMutableString alloc]init];
 int i = 0;
 if(bytes)
 {
 while (bytes[i] != '\0') 
 {
 NSString *hexByte = [NSString stringWithFormat:@"%x",bytes[i] & 0xff];///16进制数
 if([hexByte length]==1)
 [hexStr appendFormat:@"0%@", hexByte];
 else 
 [hexStr appendFormat:@"%@", hexByte];
 
 i++;
 }
 }
 NSLog(@"bytes 的16进制数为:%@",hexStr);
 return hexStr;
 }
 
 +(NSString *) parseByteArray2HexString:(Byte[]) bytes
 {
 NSMutableString *hexStr = [[NSMutableString alloc]init];
 int i = 0;
 if(bytes)
 {
 while (bytes[i] != '\0') 
 {
 NSString *hexByte = [NSString stringWithFormat:@"%x",bytes[i] & 0xff];///16进制数
 if([hexByte length]==1)
 [hexStr appendFormat:@"0%@", hexByte];
 else 
 [hexStr appendFormat:@"%@", hexByte];
 
 i++;
 }
 }
 NSLog(@"bytes 的16进制数为:%@",hexStr);
 return hexStr;
 }

以上的加密方法所在的包是CommonCrypto/CommonCryptor.h。

以上便实现了Objective-c和Java下在相同的明文和密钥的情况下生成相同明文的算法。
Base64的算法可以用你们自己写的那个,不一定必须使用我提供的这个。解密的时候还要用Base64进行密文的转换。

我的解密算法如下:

private static byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 }; 
 public static String decryptDES(String decryptString, String decryptKey)
 throws Exception {
 byte[] byteMi = Base64.decode(decryptString);
 IvParameterSpec zeroIv = new IvParameterSpec(iv);
 SecretKeySpec key = new SecretKeySpec(decryptKey.getBytes(), "DES");
 Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
 cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
 byte decryptedData[] = cipher.doFinal(byteMi);
 
 return new String(decryptedData);
 }

Base64的decode方法如下:

public static byte[] decode(String s) {
 
 ByteArrayOutputStream bos = new ByteArrayOutputStream();
 try {
 decode(s, bos);
 } catch (IOException e) {
 throw new RuntimeException();
 }
 byte[] decodedBytes = bos.toByteArray();
 try {
 bos.close();
 bos = null;
 } catch (IOException ex) {
 System.err.println("Error while decoding BASE64: " + ex.toString());
 }
 return decodedBytes;
 }
 private static void decode(String s, OutputStream os) throws IOException {
 int i = 0;
 
 int len = s.length();
 
 while (true) {
 while (i < len && s.charAt(i) <= ' ')
 i++;
 
 if (i == len)
 break;
 
 int tri = (decode(s.charAt(i)) << 18)
 + (decode(s.charAt(i + 1)) << 12)
 + (decode(s.charAt(i + 2)) << 6)
 + (decode(s.charAt(i + 3)));
 
 os.write((tri >> 16) & 255);
 if (s.charAt(i + 2) == '=')
 break;
 os.write((tri >> 8) & 255);
 if (s.charAt(i + 3) == '=')
 break;
 os.write(tri & 255);
 
 i += 4;
 }
 }
 private static int decode(char c) {
 if (c >= 'A' && c <= 'Z')
 return ((int) c) - 65;
 else if (c >= 'a' && c <= 'z')
 return ((int) c) - 97 + 26;
 else if (c >= '0' && c <= '9')
 return ((int) c) - 48 + 26 + 26;
 else
 switch (c) {
 case '+':
 return 62;
 case '/':
 return 63;
 case '=':
 return 0;
 default:
 throw new RuntimeException("unexpected code: " + c);
 }
 }

以上便实现了DES加密后的密文的解密。

Java端的测试代码如下:

String plaintext = "abcd";
 String ciphertext = DES.encryptDES(plaintext, "20120401");
 System.out.println("明文:" + plaintext);
 System.out.println("密钥:" + "20120401");
 System.out.println("密文:" + ciphertext);
 System.out.println("解密后:" + DES.decryptDES(ciphertext, "20120401"));

输出结果:

明文:abcd
密钥:20120401
密文:W7HR43/usys=
解密后:abcd

Objective-c端的测试代码如下:

NSString *plaintext = @"abcd";
 NSString *ciphertext = [EncryptUtil encryptUseDES:plaintext key:@"20120401"];
 NSLog(@"明文:%@",plaintext);
 NSLog(@"秘钥:%@",@"20120401");
 NSLog(@"密文:%@",ciphertext);

输出结果:
2012-04-05 12:00:47.348 TestEncrypt[806:f803] 明文:abcd
2012-04-05 12:00:47.350 TestEncrypt[806:f803] 秘钥:20120401
2012-04-05 12:00:47.350 TestEncrypt[806:f803] 密文:W7HR43/usys=

本文转载自:

上一篇: VMWare安装Androidx86
下一篇: WinRAR注册
山哥

山哥

粉丝 249
博文 355
码字总数 136865
作品 0
南京
程序员
私信 提问
加载中

评论(5)

iPermanant
iPermanant

引用来自“网络时空”的评论

(1)我用 iv 设为 null值得到的结果
2012-04-25 14:17:48.239 DESProject[2060:f803] 明文:abcd
2012-04-25 14:17:48.242 DESProject[2060:f803] 秘钥:20120401
2012-04-25 14:17:48.243 DESProject[2060:f803] 密文:fKS7Pa2aieM=
(2) 我用 int iv[] = {1,2,3,4,5,6,7,8};时,得到的结果是
2012-04-25 15:00:31.978 DESProject[2165:f803] 明文:abcd
2012-04-25 15:00:31.981 DESProject[2165:f803] 秘钥:20120401
2012-04-25 15:00:31.982 DESProject[2165:f803] 密文:y8YFCwZNYdY=

怎么和楼主上面贴出来的结果总不一致呢 ? 除子 iv的值外,其它的代码一模一样啊
int iv[] = {1,2,3,4,5,6,7,8};
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding, [key UTF8String], kCCKeySizeDES,iv, textBytes, dataLength, buffer, 1024, &numBytesEncrypted);

Byte vi[] = {1,2,3,4,5,6,7,8};
网络时空
网络时空
#import "DES.h"

@interface NSData(Base64Data)

- (NSString *)base64Encoding;

@end

@implementation NSData(Base64Data)

static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- (NSString *)base64Encoding;
{
if (self.length == 0)
return @"";
char *characters = malloc(self.length*3/2);
if (characters == NULL)
return @"";
int end = self.length - 3;
int index = 0;
int charCount = 0;
int n = 0;
while (index <= end) {
int d = (((int)(((char *)[self bytes])[index]) & 0x0ff) << 16)
| (((int)(((char *)[self bytes])[index + 1]) & 0x0ff) << 8)
| ((int)(((char *)[self bytes])[index + 2]) & 0x0ff);
characters[charCount++] = encodingTable[(d >> 18) & 63];
characters[charCount++] = encodingTable[(d >> 12) & 63];
characters[charCount++] = encodingTable[(d >> 6) & 63];
characters[charCount++] = encodingTable[d & 63];
index += 3;
if(n++ >= 14)
{
n = 0;
characters[charCount++] = ' ';
}
}
if(index == self.length - 2)
{
int d = (((int)(((char *)[self bytes])[index]) & 0x0ff) << 16)
| (((int)(((char *)[self bytes])[index + 1]) & 255) << 8);
characters[charCount++] = encodingTable[(d >> 18) & 63];
characters[charCount++] = encodingTable[(d >> 12) & 63];
characters[charCount++] = encodingTable[(d >> 6) & 63];
characters[charCount++] = '=';
}
else if(index == self.length - 1)
{
int d = ((int)(((char *)[self bytes])[index]) & 0x0ff) << 16;
characters[charCount++] = encodingTable[(d >> 18) & 63];
characters[charCount++] = encodingTable[(d >> 12) & 63];
characters[charCount++] = '=';
characters[charCount++] = '=';
}
NSString * rtnStr = [[NSString alloc] initWithBytesNoCopy:characters length:charCount encoding:NSUTF8StringEncoding freeWhenDone:YES];
return rtnStr;
}

@end

@implementation DES

+ (NSString *) encryptUseDES:(NSString *)plainText key:(NSString *)key
{
NSString *ciphertext = nil;
const char *textBytes = [plainText UTF8String];
NSUInteger dataLength = [plainText length];
unsigned char buffer[1024];
memset(buffer, 0, sizeof(char));
size_t numBytesEncrypted = 0;
int iv[] = {1,2,3,4,5,6,7,8};
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding, [key UTF8String], kCCKeySizeDES,iv, textBytes, dataLength, buffer, 1024, &numBytesEncrypted);

if (cryptStatus == kCCSuccess) {
NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
ciphertext = [data base64Encoding];
}
return ciphertext;
}


+(NSString *) parseByte2HexString:(Byte *) bytes
{
NSMutableString *hexStr = [[NSMutableString alloc]init];
int i = 0;
if(bytes)
{
while (bytes[i] != '\0')
{
NSString *hexByte = [NSString stringWithFormat:@"%x",bytes[i] & 0xff];///16进制数
if([hexByte length]==1)
[hexStr appendFormat:@"0%@", hexByte];
else
[hexStr appendFormat:@"%@", hexByte];
i++;
}
}
NSLog(@"bytes 的16进制数为:%@",hexStr);
return hexStr;
}


+(NSString *) parseByteArray2HexString:(Byte[]) bytes

{
NSMutableString *hexStr = [[NSMutableString alloc]init];
int i = 0;
if(bytes)
{
while (bytes[i] != '\0')
{
NSString *hexByte = [NSString stringWithFormat:@"%x",bytes[i] & 0xff];///16进制数
if([hexByte length]==1)
[hexStr appendFormat:@"0%@", hexByte];
else
[hexStr appendFormat:@"%@", hexByte];
i++;
}

}
NSLog(@"bytes 的16进制数为:%@",hexStr);
return hexStr;
}

@end
网络时空
网络时空
(1)我用 iv 设为 null值得到的结果
2012-04-25 14:17:48.239 DESProject[2060:f803] 明文:abcd
2012-04-25 14:17:48.242 DESProject[2060:f803] 秘钥:20120401
2012-04-25 14:17:48.243 DESProject[2060:f803] 密文:fKS7Pa2aieM=
(2) 我用 int iv[] = {1,2,3,4,5,6,7,8};时,得到的结果是
2012-04-25 15:00:31.978 DESProject[2165:f803] 明文:abcd
2012-04-25 15:00:31.981 DESProject[2165:f803] 秘钥:20120401
2012-04-25 15:00:31.982 DESProject[2165:f803] 密文:y8YFCwZNYdY=

怎么和楼主上面贴出来的结果总不一致呢 ? 除子 iv的值外,其它的代码一模一样啊
int iv[] = {1,2,3,4,5,6,7,8};
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding, [key UTF8String], kCCKeySizeDES,iv, textBytes, dataLength, buffer, 1024, &numBytesEncrypted);
网络时空
网络时空
encryptUseDES 这个方法中 CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
10   kCCOptionPKCS7Padding,
11   [key UTF8String], kCCKeySizeDES,
12   iv,
13   textBytes, dataLength,
14   buffer, 1024,
15   &numBytesEncrypted);

iv 是如何定义的,是什么值,请楼主贴出来一下,谢了
网络时空
网络时空
请问楼主的 oc 客户端 iv 定义在哪 ?是什么值 ?找不到值啊。。用null 值,算出来的和 java 端就会不一样了
实现ios上传加密nodejs后台解密

今天在做项目的时候遇到一个问题,我需要在ios端把上传数据加密,防止中间代理捕获信息内容并修改数据库的信息。把数据传到后台在解码,实现数据安全。 下面介绍我实现的在nodejs的加密和解密...

90后爱国
2014/08/21
1K
0
Java DESede用C++ Openssl实现

最近在看一个项目的代码 开发语言:C++ 开发环境:VS2005 但有一个很别扭的地方,就是这个项目与外界的加密算法采用DESede,但其实现是采用jni调用java vm里面的函数。 查了一下,可以用Ope...

suit
2012/10/26
2.1K
0
求一份wp7AES加解密和java AES加解密 互通源代码,谢谢

@junwong 你好,想跟你请教个问题: 服务器是用java作的,只有DES加解密,但是wp7不支持DES,现在需要求一份wp7和java AES加解密互通源代码。

junxianalan
2012/10/09
220
2
Java使用Hutool实现AES、DES加密解密

介绍 AES和DES同属对称加密算法,数据发信方将明文(原始数据)和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用...

路小磊
2017/08/07
4.2K
21
Java学习手册:Java网络编程面试问题

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/MaybeForever/article/details/95471329 1、Java学习手册:Java基础知...

浩比浩比
08/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

不就是SELECT COUNT语句吗,竟然能被面试官虐的体无完肤

数据库查询相信很多人都不陌生,所有经常有人调侃程序员就是CRUD专员,这所谓的CRUD指的就是数据库的增删改查。 在数据库的增删改查操作中,使用最频繁的就是查询操作。而在所有查询操作中,...

HollisChuang
31分钟前
6
0
乐观锁和悲观锁

乐观锁和悲观锁 在并发环境下,事务的隔离性很难保证,因此会出现很多并发一致性的问题 事务的特性:原子性、一致性、隔离性、持久性 1、丢失修改:T1和T2两个事务对同一个数据进行修改,T1先...

大瑞清_liurq
39分钟前
5
0
Scrum敏捷价值观与原则

Scrum是一种迭代式增量软件开发过程,通常用于敏捷软件开发。如果还不知道Scrum敏捷开发的朋友们,请出门左转,点击 Scrum 了解。 敏捷价值观 个体和互动 高于 流程和工具 工作的软件 高于 ...

醉美閑聖
39分钟前
5
0
android焦点

final RelativeLayout relativeLayout=new RelativeLayout(context); relativeLayout.setClickable(true); relativeLayout.setFocusable(true); rel......

安卓工程师王恒
41分钟前
4
0
IP地址分配与中继设备简介

1. TCP/IP模型 TCP/IP协议是在OSI参考模型出现之间就被开发的,并广泛部署在计算机网络中。但是,后来由于概念混淆,TCP/IP模型的层次和名称往往与OSI模型的层次名称相互借用。如图1.所示。 ...

xiangyunyan
43分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部