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=





     

  • 相关阅读:
    Zabbix5 Frame 嵌套
    Zabbix5 对接 SAML 协议 SSO
    CentOS7 安装 Nexus
    CentOS7 安装 SonarQube
    GitLab 后台修改用户密码
    GitLab 查看版本号
    GitLab Admin Area 500 Error
    Linux 安装 PostgreSQL
    Liger ui grid 参数
    vue.js 是一个怪东西
  • 原文地址:https://www.cnblogs.com/janken/p/2432930.html
Copyright © 2011-2022 走看看