zoukankan      html  css  js  c++  java
  • iOS,Android,WP, .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="key";
    
        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;
        }    
        
    }

     Windows Phone&Windows Store:

     public static string Encrypt(string toEncrypt)
            {
               
                 //创建算法提供器
                var symmetricAlgorithm = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesEcbPkcs7);
                //key处理
                IBuffer tempKey = CryptographicBuffer.ConvertStringToBinary(key, BinaryStringEncoding.Utf8);
                CryptographicKey cryptKey = symmetricAlgorithm.CreateSymmetricKey(tempKey);
                // 将需要加密的数据转换为 IBuffer 类型
                var dateBuffer = CryptographicBuffer.ConvertStringToBinary(toEncrypt, BinaryStringEncoding.Utf8);
                
                try
                {
                    // 加密数据
                    var encrypted = CryptographicEngine.Encrypt(cryptKey,dateBuffer,null);
                   // Debug.WriteLine(encrypted);
                   return CryptographicBuffer.EncodeToBase64String(encrypted);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
    
                return null;
            }
  • 相关阅读:
    BZOJ 1951: [Sdoi2010]古代猪文( 数论 )
    BZOJ 1176: [Balkan2007]Mokia( CDQ分治 + 树状数组 )
    BZOJ 1066: [SCOI2007]蜥蜴( 最大流 )
    BZOJ 1935: [Shoi2007]Tree 园丁的烦恼( 差分 + 离散化 + 树状数组 )
    BZOJ 1297: [SCOI2009]迷路( dp + 矩阵快速幂 )
    BZOJ 1406: [AHOI2007]密码箱( 数论 )
    BZOJ 1876: [SDOI2009]SuperGCD( 更相减损 + 高精度 )
    spfa2
    spfa
    bellmanford队列优化
  • 原文地址:https://www.cnblogs.com/mantgh/p/4244891.html
Copyright © 2011-2022 走看看