原文: iOS,Android,.NET通用AES加密算法

这两天为移动App开发API,结果实现加密验证时碰到一大坑。这里不得不吐槽下又臭又硬的iOS,Windows Server无法解密出正确的结果,Android则可以,后来使用了通用的AES256加密算法才最终搞定。

搞服务器端小伙伴没有接触过iOS,所以也没料到过这种情形。他使用了AES128 with IV的加密算法,Android端可以顺利通过加密验证。

但是iOS端使用AES128算法后出现问题,虽然可以在本地加密解密,但是无法被服务器解密成功。

后来经过多方查找,才了解到一个蛋疼的事实,iOS只支持AES PKCS7Padding算法,在服务器端修改为响应算法后,顺利通过。

这里主要参考一篇博文,以下给出通用AES算法:

Objective-C:

//头文件
#import
<Foundation/Foundation.h>@interface NSData (AES)- (NSData *)AES256EncryptWithKey:(NSString *)key;- (NSData *)AES256DecryptWithKey:(NSString *)key;@end

实现代码:

#import "NSData+AES256.h"#import <CommonCrypto/CommonCryptor.h>@implementation NSData (AES)-(NSData *)AES256EncryptWithKey:(NSString *)key {    // 'key' should be 32 bytes for AES256, will be null-padded otherwise    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)        // fetch key data    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];        NSUInteger dataLength = [self length];        //See the doc: For block ciphers, the output size will always be less than or    //equal to the input size plus the size of one block.    //That's why we need to add the size of one block here    size_t bufferSize = dataLength + kCCBlockSizeAES128;    void *buffer = malloc(bufferSize);        size_t numBytesEncrypted = 0;    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,                                          keyPtr, kCCKeySizeAES256,                                          NULL /* initialization vector (optional) */,                                          [self bytes], dataLength, /* input */                                          buffer, bufferSize, /* output */                                          &numBytesEncrypted);    if (cryptStatus == kCCSuccess) {        //the returned NSData takes ownership of the buffer and will free it on deallocation        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];    }        free(buffer); //free the buffer;    return nil;}-(NSData *)AES256DecryptWithKey:(NSString *)key {    // 'key' should be 32 bytes for AES256, will be null-padded otherwise    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)        // fetch key data    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];        NSUInteger dataLength = [self length];        //See the doc: For block ciphers, the output size will always be less than or    //equal to the input size plus the size of one block.    //That's why we need to add the size of one block here    size_t bufferSize = dataLength + kCCBlockSizeAES128;    void *buffer = malloc(bufferSize);        size_t numBytesDecrypted = 0;    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,                                          keyPtr, kCCKeySizeAES256,                                          NULL /* initialization vector (optional) */,                                          [self bytes], dataLength, /* input */                                          buffer, bufferSize, /* output */                                          &numBytesDecrypted);        if (cryptStatus == kCCSuccess) {        //the returned NSData takes ownership of the buffer and will free it on deallocation        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];    }        free(buffer); //free the buffer;    return nil;}@end

C#:

#region        /// <summary>        /// 256位AES加密        /// </summary>        /// <param name="toEncrypt"></param>        /// <returns></returns>        public static string Encrypt(string toEncrypt)        {            // 256-AES key                byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);            RijndaelManaged rDel = new RijndaelManaged();            rDel.Key = keyArray;            rDel.Mode = CipherMode.ECB;            rDel.Padding = PaddingMode.PKCS7;            ICryptoTransform cTransform = rDel.CreateEncryptor();            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);            return Convert.ToBase64String(resultArray, 0, resultArray.Length);        }        /// <summary>        /// 256位AES解密        /// </summary>        /// <param name="toDecrypt"></param>        /// <returns></returns>        public static string Decrypt(string toDecrypt)        {            // 256-AES key                byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);            byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);            RijndaelManaged rDel = new RijndaelManaged();            rDel.Key = keyArray;            rDel.Mode = CipherMode.ECB;            rDel.Padding = PaddingMode.PKCS7;            ICryptoTransform cTransform = rDel.CreateDecryptor();            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);            return UTF8Encoding.UTF8.GetString(resultArray);        }        #endregion

Java

import java.io.UnsupportedEncodingException;import java.security.InvalidAlgorithmParameterException;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.util.Arrays;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import android.util.Base64;public class AESUtils {    /**      * 加密      * @param content 需要加密的内容      * @param password  加密密码      * @return      */      private static String Key="GcA*23jKJf0df09Osf09834ljlJF0920";    public static String encode(String stringToEncode) throws NullPointerException {        try {            SecretKeySpec skeySpec = getKey(Key);            byte[] clearText = stringToEncode.getBytes("UTF8");            final byte[] iv = new byte[16];            Arrays.fill(iv, (byte) 0x00);            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);            String encrypedValue = Base64.encodeToString(cipher.doFinal(clearText), Base64.DEFAULT);            return encrypedValue;                    } catch (InvalidKeyException e) {            e.printStackTrace();        } catch (UnsupportedEncodingException e) {            e.printStackTrace();        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        } catch (BadPaddingException e) {            e.printStackTrace();        } catch (NoSuchPaddingException e) {            e.printStackTrace();        } catch (IllegalBlockSizeException e) {            e.printStackTrace();        } catch (InvalidAlgorithmParameterException e) {            e.printStackTrace();        }        return "";    }                 private static SecretKeySpec getKey(String password) throws UnsupportedEncodingException {        int keyLength = 256;        byte[] keyBytes = new byte[keyLength / 8];        Arrays.fill(keyBytes, (byte) 0x0);        byte[] passwordBytes = password.getBytes("UTF-8");        int length = passwordBytes.length < keyBytes.length ? passwordBytes.length : keyBytes.length;        System.arraycopy(passwordBytes, 0, keyBytes, 0, length);        SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");        return key;    }        }

更多相关文章

  1. android 图片占用进程的内存算法
  2. Android逆向之旅---Android中锁屏密码算法解析以及破解方案
  3. Android客户端Socket连接PC服务器端(加评论)
  4. android客户端向服务器端验证登陆方法的实现2
  5. Java android ios 通用可逆des加密算法
  6. Android客户端上传文件到服务器端
  7. Android高性能编码三:数据结构和算法优化

随机推荐

  1. [Android]ScrollView和ListView套用冲突
  2. 狂刷Android范例之2:剪贴板范例
  3. 转:深入解读Linux与Android的相互关系
  4. Android之用自定义的shape去实现shadow效
  5. Android发展以及历史版本号
  6. Android Camera的接口与架构介绍
  7. Android - Layout时发生'Unfortunately x
  8. Android(安卓)热补丁技术——资源的热修
  9. 关于 android app 返回键模拟 home键 功
  10. android前后摄像头切换