zoukankan      html  css  js  c++  java
  • 关于Objectivec和Java下DES加密保持一致的方式

    首先谢谢4楼id0096替我修改的bug,当时由于只用于密码加密,所以没有测试中文,本次更新添加了objective-c的des解密和中文加密失败的修正。

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

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

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

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

     1 public class Base64 {
    2 private static final char[] legalChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    3 .toCharArray();
    4
    5 /**
    6 * data[]进行编码
    7 *
    8 * @param data
    9 * @return
    10 */
    11 public static String encode(byte[] data) {
    12 int start = 0;
    13 int len = data.length;
    14 StringBuffer buf = new StringBuffer(data.length * 3 / 2);
    15
    16 int end = len - 3;
    17 int i = start;
    18 int n = 0;
    19
    20 while (i <= end) {
    21 int d = ((((int) data[i]) & 0x0ff) << 16)
    22 | ((((int) data[i + 1]) & 0x0ff) << 8)
    23 | (((int) data[i + 2]) & 0x0ff);
    24
    25 buf.append(legalChars[(d >> 18) & 63]);
    26 buf.append(legalChars[(d >> 12) & 63]);
    27 buf.append(legalChars[(d >> 6) & 63]);
    28 buf.append(legalChars[d & 63]);
    29
    30 i += 3;
    31
    32 if (n++ >= 14) {
    33 n = 0;
    34 buf.append(" ");
    35 }
    36 }
    37
    38 if (i == start + len - 2) {
    39 int d = ((((int) data[i]) & 0x0ff) << 16)
    40 | ((((int) data[i + 1]) & 255) << 8);
    41
    42 buf.append(legalChars[(d >> 18) & 63]);
    43 buf.append(legalChars[(d >> 12) & 63]);
    44 buf.append(legalChars[(d >> 6) & 63]);
    45 buf.append("=");
    46 } else if (i == start + len - 1) {
    47 int d = (((int) data[i]) & 0x0ff) << 16;
    48
    49 buf.append(legalChars[(d >> 18) & 63]);
    50 buf.append(legalChars[(d >> 12) & 63]);
    51 buf.append("==");
    52 }
    53
    54 return buf.toString();
    55 }
    56

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

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

     1     /**将二进制转换成16进制 
    2 * @param buf
    3 * @return String
    4 */
    5 public static String parseByte2HexStr(byte buf[]) {
    6 StringBuffer sb = new StringBuffer();
    7 for (int i = 0; i < buf.length; i++) {
    8 String hex = Integer.toHexString(buf[i] & 0xFF);
    9 if (hex.length() == 1) {
    10 hex = '0' + hex;
    11 }
    12 sb.append(hex.toUpperCase());
    13 }
    14 return sb.toString();
    15 }

    下面是Objective-c在iOS上实现的DES加密算法:

     1 const Byte iv[] = {1,2,3,4,5,6,7,8};
     2 +(NSString *) encryptUseDES:(NSString *)plainText key:(NSString *)key
     3 {
     4     NSString *ciphertext = nil;
     5     NSData *textData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
     6     NSUInteger dataLength = [textData length];
     7     unsigned char buffer[1024];
     8     memset(buffer, 0, sizeof(char));
     9     size_t numBytesEncrypted = 0;
    10     CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
    11                                           kCCOptionPKCS7Padding,
    12                                           [key UTF8String], kCCKeySizeDES,
    13                                           iv,
    14                                           [textData bytes], dataLength,
    15                                           buffer, 1024,
    16                                           &numBytesEncrypted);
    17     if (cryptStatus == kCCSuccess) {
    18         NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
    19         ciphertext = [Base64 encode:data];
    20     }
    21     return ciphertext;
    22 }

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

     1 +(NSString *) parseByte2HexString:(Byte *) bytes
    2 {
    3 NSMutableString *hexStr = [[NSMutableString alloc]init];
    4 int i = 0;
    5 if(bytes)
    6 {
    7 while (bytes[i] != '\0')
    8 {
    9 NSString *hexByte = [NSString stringWithFormat:@"%x",bytes[i] & 0xff];///16进制数
    10 if([hexByte length]==1)
    11 [hexStr appendFormat:@"0%@", hexByte];
    12 else
    13 [hexStr appendFormat:@"%@", hexByte];
    14
    15 i++;
    16 }
    17 }
    18 NSLog(@"bytes 的16进制数为:%@",hexStr);
    19 return hexStr;
    20 }
    21
    22 +(NSString *) parseByteArray2HexString:(Byte[]) bytes
    23 {
    24 NSMutableString *hexStr = [[NSMutableString alloc]init];
    25 int i = 0;
    26 if(bytes)
    27 {
    28 while (bytes[i] != '\0')
    29 {
    30 NSString *hexByte = [NSString stringWithFormat:@"%x",bytes[i] & 0xff];///16进制数
    31 if([hexByte length]==1)
    32 [hexStr appendFormat:@"0%@", hexByte];
    33 else
    34 [hexStr appendFormat:@"%@", hexByte];
    35
    36 i++;
    37 }
    38 }
    39 NSLog(@"bytes 的16进制数为:%@",hexStr);
    40 return hexStr;
    41 }

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

    以上便实现了Objective-c和Java下在相同的明文和密钥的情况下生成相同明文的算法。

    Base64的算法可以用你们自己写的那个,不一定必须使用我提供的这个。解密的时候还要用Base64进行密文的转换。

    iOS下的Base64算法在后面 。

    JAVA下的解密算法如下:

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

    Base64的decode方法如下:

     1   public static byte[] decode(String s) {
    2
    3 ByteArrayOutputStream bos = new ByteArrayOutputStream();
    4 try {
    5 decode(s, bos);
    6 } catch (IOException e) {
    7 throw new RuntimeException();
    8 }
    9 byte[] decodedBytes = bos.toByteArray();
    10 try {
    11 bos.close();
    12 bos = null;
    13 } catch (IOException ex) {
    14 System.err.println("Error while decoding BASE64: " + ex.toString());
    15 }
    16 return decodedBytes;
    17 }
    18 private static void decode(String s, OutputStream os) throws IOException {
    19 int i = 0;
    20
    21 int len = s.length();
    22
    23 while (true) {
    24 while (i < len && s.charAt(i) <= ' ')
    25 i++;
    26
    27 if (i == len)
    28 break;
    29
    30 int tri = (decode(s.charAt(i)) << 18)
    31 + (decode(s.charAt(i + 1)) << 12)
    32 + (decode(s.charAt(i + 2)) << 6)
    33 + (decode(s.charAt(i + 3)));
    34
    35 os.write((tri >> 16) & 255);
    36 if (s.charAt(i + 2) == '=')
    37 break;
    38 os.write((tri >> 8) & 255);
    39 if (s.charAt(i + 3) == '=')
    40 break;
    41 os.write(tri & 255);
    42
    43 i += 4;
    44 }
    45 }
    46 private static int decode(char c) {
    47 if (c >= 'A' && c <= 'Z')
    48 return ((int) c) - 65;
    49 else if (c >= 'a' && c <= 'z')
    50 return ((int) c) - 97 + 26;
    51 else if (c >= '0' && c <= '9')
    52 return ((int) c) - 48 + 26 + 26;
    53 else
    54 switch (c) {
    55 case '+':
    56 return 62;
    57 case '/':
    58 return 63;
    59 case '=':
    60 return 0;
    61 default:
    62 throw new RuntimeException("unexpected code: " + c);
    63 }
    64 }

    Objective-c在下的DES解密算法:

     1 +(NSString *)decryptUseDES:(NSString *)cipherText key:(NSString *)key
     2 {
     3     NSString *plaintext = nil;
     4     NSData *cipherdata = [Base64 decode:cipherText];
     5     unsigned char buffer[1024];
     6     memset(buffer, 0, sizeof(char));
     7     size_t numBytesDecrypted = 0;
     8     CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmDES,
     9                                           kCCOptionPKCS7Padding,
    10                                           [key UTF8String], kCCKeySizeDES,
    11                                           iv,
    12                                           [cipherdata bytes], [cipherdata length],
    13                                           buffer, 1024,
    14                                           &numBytesDecrypted);
    15     if(cryptStatus == kCCSuccess) {
    16         NSData *plaindata = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesDecrypted];
    17         plaintext = [[NSString alloc]initWithData:plaindata encoding:NSUTF8StringEncoding];
    18     }
    19     return plaintext;
    20 }

    下面是objective-c 实现的Base64工具对象,当然你也可以选择使用google的那个Base64类——GTMBase64(功能很强大),初步测试使用GTMBase64和使用我写的这个Base64效果都是一样的。

      1 static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
      2 
      3 @interface Base64()
      4 +(int)char2Int:(char)c;
      5 @end
      6 
      7 @implementation Base64
      8 
      9 +(NSString *)encode:(NSData *)data
     10 {
     11     if (data.length == 0)
     12         return nil;
     13     
     14     char *characters = malloc(data.length * 3 / 2);
     15     
     16     if (characters == NULL)
     17         return nil;
     18     
     19     int end = data.length - 3;
     20     int index = 0;
     21     int charCount = 0;
     22     int n = 0;
     23     
     24     while (index <= end) {
     25         int d = (((int)(((char *)[data bytes])[index]) & 0x0ff) << 16)
     26         | (((int)(((char *)[data bytes])[index + 1]) & 0x0ff) << 8)
     27         | ((int)(((char *)[data bytes])[index + 2]) & 0x0ff);
     28         
     29         characters[charCount++] = encodingTable[(d >> 18) & 63];
     30         characters[charCount++] = encodingTable[(d >> 12) & 63];
     31         characters[charCount++] = encodingTable[(d >> 6) & 63];
     32         characters[charCount++] = encodingTable[d & 63];
     33         
     34         index += 3;
     35         
     36         if(n++ >= 14)
     37         {
     38             n = 0;
     39             characters[charCount++] = ' ';
     40         }
     41     }
     42     
     43     if(index == data.length - 2)
     44     {
     45         int d = (((int)(((char *)[data bytes])[index]) & 0x0ff) << 16)
     46         | (((int)(((char *)[data bytes])[index + 1]) & 255) << 8);
     47         characters[charCount++] = encodingTable[(d >> 18) & 63];
     48         characters[charCount++] = encodingTable[(d >> 12) & 63];
     49         characters[charCount++] = encodingTable[(d >> 6) & 63];
     50         characters[charCount++] = '=';
     51     }
     52     else if(index == data.length - 1)
     53     {
     54         int d = ((int)(((char *)[data bytes])[index]) & 0x0ff) << 16;
     55         characters[charCount++] = encodingTable[(d >> 18) & 63];
     56         characters[charCount++] = encodingTable[(d >> 12) & 63];
     57         characters[charCount++] = '=';
     58         characters[charCount++] = '=';
     59     }
     60     NSString * rtnStr = [[NSString alloc] initWithBytesNoCopy:characters length:charCount encoding:NSUTF8StringEncoding freeWhenDone:YES];
     61     return rtnStr;
     62 
     63 }
     64 
     65 +(NSData *)decode:(NSString *)data
     66 {
     67     if(data == nil || data.length <= 0) {
     68         return nil;
     69     }
     70     NSMutableData *rtnData = [[NSMutableData alloc]init];
     71     int slen = data.length;
     72     int index = 0;
     73     while (true) {
     74         while (index < slen && [data characterAtIndex:index] <= ' ') {
     75             index++;
     76         }
     77         if (index >= slen || index  + 3 >= slen) {
     78             break;
     79         }
     80 
     81         int byte = ([self char2Int:[data characterAtIndex:index]] << 18) + ([self char2Int:[data characterAtIndex:index + 1]] << 12) + ([self char2Int:[data characterAtIndex:index + 2]] << 6) + [self char2Int:[data characterAtIndex:index + 3]];
     82         Byte temp1 = (byte >> 16) & 255;
     83         [rtnData appendBytes:&temp1 length:1];
     84         if([data characterAtIndex:index + 2] == '=') {
     85             break;
     86         }
     87         Byte temp2 = (byte >> 8) & 255;
     88         [rtnData appendBytes:&temp2 length:1];
     89         if([data characterAtIndex:index + 3] == '=') {
     90             break;
     91         }
     92         Byte temp3 = byte & 255;
     93         [rtnData appendBytes:&temp3 length:1];
     94         index += 4;
     95 
     96     }
     97     return rtnData;
     98 }
     99 
    100 +(int)char2Int:(char)c
    101 {
    102     if (c >= 'A' && c <= 'Z') {
    103         return c - 65;
    104     } else if (c >= 'a' && c <= 'z') {
    105         return c - 97 + 26;
    106     } else if (c >= '0' && c <= '9') {
    107         return c - 48 + 26 + 26;
    108     } else {
    109         switch(c) {
    110             case '+':
    111                 return 62;
    112             case '/':
    113                 return 63;
    114             case '=':
    115                 return 0;
    116             default:
    117                 return -1;
    118         }
    119     }
    120 }
    121 
    122 @end

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

    Java端的测试代码如下:

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

    输出结果:

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


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

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

    输出结果:

    1 2012-04-05 12:00:47.348 TestEncrypt[806:f803] 明文:abcd
    2 2012-04-05 12:00:47.350 TestEncrypt[806:f803] 秘钥:20120401
    3 2012-04-05 12:00:47.350 TestEncrypt[806:f803] 密文:W7HR43/usys=





     

  • 相关阅读:
    数据库面试题
    数据库面试题
    DevExpress GridView 鼠标悬停颜色追踪(行或单元格)
    DevExpress GridView 鼠标悬停颜色追踪(行或单元格)
    2015最新最全最详细的配置win8.1开启IIS和ASP
    2015最新最全最详细的配置win8.1开启IIS和ASP
    打开IIS管理器命令cmd
    打开IIS管理器命令cmd
    C#在方法或属性中使用sealed时的操作与原理
    C#在方法或属性中使用sealed时的操作与原理
  • 原文地址:https://www.cnblogs.com/janken/p/2432930.html
Copyright © 2011-2022 走看看