# Combining AES encryption with Base64 encoding on iOS

Language: en
Canonical: [Combining AES encryption with Base64 encoding on iOS](<https://allluckly.cn/en/journal/2016-03-30-combining-aes-encryption-with-base64-encoding-on-ios/>)
中文：[中文 HTML](<https://allluckly.cn/aes/AES>)
English: [English HTML](<https://allluckly.cn/en/journal/2016-03-30-combining-aes-encryption-with-base64-encoding-on-ios/>)
Published: 2016-03-30T00:00:00+08:00
Modified: 2026-10-23T10:34:14+08:00
Author: [Bison](<https://allluckly.cn/about/>)

Defines categories for NSData and NSString to demonstrate a workflow combining AES encryption and decryption with Base64 encoding. It notes that the client and server must agree on the same key and provides a complete demonstration project.

Originally credited to Bison. Content is retained as published.

English translation of the [Chinese original](<https://allluckly.cn/aes/AES>), translated on 2026-10-23. The article body uses automated translation; app descriptions, historical reading notes and video subtitles receive separate editorial checks. Original publication dates, attribution, code and version notes are retained.

**Before you read** This technical note dates from 2015–2017. The examples have not been rerun as part of this archive update. Published in 2016. The example uses a CommonCrypto category implementation from that period; Base64 serves as encoding in the workflow.

> "App-data security concerns us as developers. Basic MD5/Base64 approaches no longer satisfy current data-security standards. This article briefly introduces combined AES and Base64 encoding, encryption and decryption."

AES, Advanced Encryption Standard, also called Rijndael in cryptography, is a block-cipher standard adopted by the US federal government to replace DES. Widely analysed and used worldwide, it followed a five-year selection process. NIST published it as FIPS PUB 197 on November 26, 2001, and it became effective on May 26, 2002. By 2006 it was among the most popular symmetric-key encryption algorithms.

The explanation above comes from Baidu Baike.

Now I will demonstrate usage in code. Create an NSData category named AES, producing NSData+AES, then import the following headers:

```
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
```

Add encryption and decryption methods for external callers. The .h file becomes:

```
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>

@interface NSData (AES)

//加密
- (NSData *) AES256_Encrypt:(NSString *)key;

//解密
- (NSData *) AES256_Decrypt:(NSString *)key;

//追加64编码
- (NSString *)newStringInBase64FromData;

//同上64编码
+ (NSString*)base64encode:(NSString*)str;


@end
```

Implement these methods in order in the .m file:

```
#import "NSData+AES.h"

static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

@implementation NSData (AES)

//加密
- (NSData *) AES256_Encrypt:(NSString *)key{
    char keyPtr[kCCKeySizeAES256+1];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [self length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,
    kCCOptionPKCS7Padding | kCCOptionECBMode,
    keyPtr, kCCBlockSizeAES128,
    NULL,
    [self bytes], dataLength,
    buffer, bufferSize,
    &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    free(buffer);
    return nil;
}

//解密
- (NSData *) AES256_Decrypt:(NSString *)key{

    char keyPtr[kCCKeySizeAES256+1];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [self length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128,
    kCCOptionPKCS7Padding | kCCOptionECBMode,
    keyPtr, kCCBlockSizeAES128,
    NULL,
    [self bytes], dataLength,
    buffer, bufferSize,
    &numBytesDecrypted);
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];

    }
    free(buffer);
    return nil;
}

//追加64编码
- (NSString *)newStringInBase64FromData            

{

    NSMutableString *dest = [[NSMutableString alloc] initWithString:@""];

    unsigned char * working = (unsigned char *)[self bytes];

    int srcLen = (int)[self length];

    for (int i=0; i<srcLen; i += 3) {

        for (int nib=0; nib<4; nib++) {

            int byt = (nib == 0)?0:nib-1;

            int ix = (nib+1)*2;

            if (i+byt >= srcLen) break;

            unsigned char curr = ((working[i+byt] << (8-ix)) & 0x3F);

            if (i+nib < srcLen) curr |= ((working[i+nib] >> ix) & 0x3F);

            [dest appendFormat:@"%c", base64[curr]];

        }

    }

    return dest;

}



+ (NSString*)base64encode:(NSString*)str

{

    if ([str length] == 0)

    return @"";

    const char *source = [str UTF8String];

    int strlength  = (int)strlen(source);

    char *characters = malloc(((strlength + 2) / 3) * 4);

    if (characters == NULL)

    return nil;

    NSUInteger length = 0;

    NSUInteger i = 0;

    while (i < strlength) {

        char buffer[3] = {0,0,0};

        short bufferLength = 0;

        while (bufferLength < 3 && i < strlength)

        buffer[bufferLength++] = source[i++];

        characters[length++] = base64[(buffer[0] & 0xFC) >> 2];

        characters[length++] = base64[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)];

        if (bufferLength > 1)

        characters[length++] = base64[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)];

        else characters[length++] = '=';

        if (bufferLength > 2)

        characters[length++] = base64[buffer[2] & 0x3F];

        else characters[length++] = '=';

    }

    NSString *g = [[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES];


    return g;

}



@end
```

That completes the AES+Base64 approach. Next is AES-only string encryption.  
 Similarly, create an NSString category named AES, producing NSString+AES, and import these headers:

```
#import "NSData+AES.h"
```

Declare the encryption and decryption methods in the .h file as follows:

```
#import <Foundation/Foundation.h>
#import "NSData+AES.h"

@interface NSString (AES)

//加密
- (NSString *) AES256_Encrypt:(NSString *)key;

//解密
- (NSString *) AES256_Decrypt:(NSString *)key;

@end
```

Implementation in the .m file

```
//加密
- (NSString *) AES256_Encrypt:(NSString *)key{
    const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *data = [NSData dataWithBytes:cstr length:self.length];
    //对数据进行加密
    NSData *result = [data AES256_Encrypt:key];

    //转换为2进制字符串
    if (result && result.length > 0) {

    Byte *datas = (Byte*)[result bytes];
    NSMutableString *output = [NSMutableString stringWithCapacity:result.length * 2];
    for(int i = 0; i < result.length; i++){
        [output appendFormat:@"%02x", datas[i]];
    }
    return output;
    }
    return nil;
}

//解密
- (NSString *) AES256_Decrypt:(NSString *)key{
    //转换为2进制Data
    NSMutableData *data = [NSMutableData dataWithCapacity:self.length / 2];
    unsigned char whole_byte;
    char byte_chars[3] = {'\0','\0','\0'};
    int i;
    for (i=0; i < [self length] / 2; i++) {
    byte_chars[0] = [self characterAtIndex:i*2];
    byte_chars[1] = [self characterAtIndex:i*2+1];
    whole_byte = strtol(byte_chars, NULL, 16);
    [data appendBytes:&whole_byte length:1];
    }

    //对数据进行解密
    NSData* result = [data AES256_Decrypt:key];
    if (result && result.length > 0) {
        return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
    }
    return nil;
}
```

The encryption files are largely ready. Here is a simple usage example:

```
#import "ViewController.h"
#import "NSString+AES.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    //字符串加密
    NSString *key = @"12345678";//Key是和后台约定的key哦，不然无法解密....

    NSString *secret = @"aes Bison base64";


    NSLog(@"字符串加密---%@",[secret AES256_Encrypt:key]);

    //字符串解密
    NSLog(@"字符串解密---%@",[[secret AES256_Encrypt:key] AES256_Decrypt:key]);


    //NSData加密+base64

    NSData *plain = [secret dataUsingEncoding:NSUTF8StringEncoding];

    NSData *cipher = [plain AES256_Encrypt:key];

    NSLog(@"NSData加密+base64++++%@",[cipher newStringInBase64FromData]);


    //解密

    plain = [cipher AES256_Decrypt:key];

    NSLog(@"NSData解密+base64++++%@", [[NSString alloc] initWithData:plain encoding:NSUTF8StringEncoding]);

}


@end
```

Running it prints the following:

```
2016-03-30 17:31:55.686 AES_256[14242:198853] 字符串加密---07815ca46d20acc3ba4e43d6930c7537496e851a36dbeac34fa30c5796089b02
2016-03-30 17:31:55.687 AES_256[14242:198853] 字符串解密---aes Bison base64
2016-03-30 17:31:55.687 AES_256[14242:198853] NSData加密+base64++++B4FcpG0grMO6TkPWkwx1N0luhRo22+rDT6MMV5YImwI
2016-03-30 17:31:55.687 AES_256[14242:198853] NSData解密+base64++++aes Bison base64
```

## The Key must match the key agreed with the backend; otherwise decryption fails.

Finally, here is [Download the demo](<https://github.com/AllLuckly/LBAES/tree/master>)

---

Recommended reading: [A beginner developer's review of 2015](<https://allluckly.cn/en/journal/2016-02-01-a-beginner-developer-s-review-of-2015/>)

