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

原文: 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;

    }    

    

}

 

你可能感兴趣的:(android)