问题
I try to encrypt some string using AES algorithm with ECB option.
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode,
encryptionKey, kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
But func returns kCCAlignmentError (-4303)
Then I try to align data:
unsigned long diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
unsigned long newSize = 0;
if (diff > 0) {
newSize = dataLength + diff;
}
char dataPtr[newSize];
memcpy(dataPtr, [self bytes], [self length]);
for(int i = 0; i < diff; i++) {
dataPtr[i + dataLength] = 0x20;
}
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode,
encryptionKey, kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
dataPtr, sizeof(dataPtr), /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
input string
"test_string,test2"
result is
jxtFOhYpgBVieM90zx9oDanqBkcsVAvRRJsM4GL3cio=
On Android result is
jxtFOhYpgBVieM90zx9oDUfV7v43WFv7F5bzErfxrL8=
What did I wrong?
回答1:
Simply AES is a block cypher which means it requires it's input data to be a multiple of the block size (16-bytes for AES). Your input data is 17 bytes thus th alignment error. (It is not talking about the alignment in memory).
The way to handle this is to specify PKCS#7 padding in the options:
kCCOptionPKCS7Padding | kCCOptionECBMode
The input data will be padded to a block multiple and on decryption the padding will be removed. To allow this on encryption it is necessary to increase the output buffer by one block size.
Consider not using [ECB mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29 (Scroll down to the Penguin), it is not secure.
If you are using mcrypt on Android: don't, it is abandonware and does not support standard padding, only null padding. Instead consider defuse or RNCryptor which is a full secure implementation is is available for iOS and Java.
If you do use mcrypt you will need to add your own PKCS#7 padding.
Here is example code:
+ (NSData *)doCipher:(NSData *)dataIn
key:(NSData *)symmetricKey
context:(CCOperation)encryptOrDecrypt // kCCEncrypt or kCCDecrypt
{
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0; // Number of bytes moved to buffer.
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
ccStatus = CCCrypt( encryptOrDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding | kCCOptionECBMode,
symmetricKey.bytes,
kCCKeySizeAES128,
0,
dataIn.bytes, dataIn.length,
dataOut.mutableBytes, dataOut.length,
&cryptBytes);
if (ccStatus != kCCSuccess) {
NSLog(@"CCCrypt status: %d", ccStatus);
}
dataOut.length = cryptBytes;
return dataOut;
}
Example PHP PKCS#7 padding:
Add PKCS#7 padding
$padLength = $blockSize - (strlen($clearText) % $blockSize);
$clearText = $clearText . str_repeat(chr($padLength), $padLength);
Strip PKCS#7 padding
$padLength = ord($cryptText[strlen($cryptText)-1]);
$cryptText = substr($cryptText, 0, strlen($cryptText) - $padLength);
回答2:
Although AES/ECB is not really recommended. This post explains why there's an alignment error and how to deal with it.
Alignment error almost means there is something wrong with the sizes.
Why is there an error?
A block cipher works on units of a fixed size (known as a block size), but messages come in a variety of lengths. So some modes (namely ECB and CBC) require that the final block be padded before encryption. (Source: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_(ECB) )
Since AES ECB doesn't do the padding for you, you have to process the raw data before encrypting it.
Of course you can use kCCOptionPKCS7Padding
when permitted, but since this thread is talking about ECB mode and alignment error, let's just focus on how to pad the data.
How many bytes should I pad?
The number of plain data bytes has to be an integral multiple of the current algorithm's block size.
That is, if your block size is kCCBlockSizeAES128
(16), you have to pad your data into "the nearest multiple of the block size" (16*n).
For example,
if your data is "abc" (3 bytes), then you have to pad your data into 16 bytes;
if your data is "1234567890123456" (16 bytes), then you have to pad it into 32 bytes.
0 ~ 15 bytes => pad to 16 bytes
16 ~ 31 bytes => pad to 32 bytes
32 ~ 47 bytes => pad to 48 bytes
... and so on
What is the value of the bytes to be padded?
If you have to pad 1 byte, then the 1 byte you pad would be '01';
If you have to pad 2 bytes, then the 2 bytes you pad would be '02';
...
If you have to pad 16 bytes, then the 16 bytes you pad would be '10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10'
Example of raw data and padded data before encryption
Example 1. (under block size 16)
Original data string: "abc" (3 bytes)
Data Bytes: "61 62 63"
Padded Data Bytes: "61 62 63 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d"
Explanation:
Data are 3 bytes, so the nearest multiple of the block size is 16 bytes.
So there are 13 bytes to be padded.
And 13 in hex would be 0xd, so '0d' is padded for 13 times.
Let's have another example of data that is exactly a multiple of block size.
Example 2. (under block size 16)
Original data string: "1234567890123456" (16 bytes)
Data Bytes: "31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36"
Padded Data Bytes: "31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10"
Explanation:
Data are 16 bytes, so the nearest multiple of the block size is 32 bytes.
So there are 16 bytes to be padded.
And 16 in hex would be 0x10, so '10' is padded for 16 times.
To pad the data in Objective-C
Here is an example of how to pad your data when using AES/ECB encryption mode:
+ (NSData *)addPaddingBeforeEncryptWithAESECB:(NSData *) data{
//Length has to be the nearest multiple of the block size
int cipherLen = (int)(data.length/kAlgorithmBlockSize + 1)*kAlgorithmBlockSize;
NSMutableData *newData = [NSMutableData dataWithLength:cipherLen];
newData = [data mutableCopy];
//How many bytes to be padded
int bytesToAddOn = kAlgorithmBlockSize - data.length%kAlgorithmBlockSize;
//Each byte in hex
char byteToAdd = bytesToAddOn & 0xff;
char *buffer = malloc(bytesToAddOn * sizeof byteToAdd);
memset (buffer, byteToAdd, sizeof (char) * bytesToAddOn);
[newData appendBytes:buffer length:bytesToAddOn];
return newData;
}
Full example of AES ECB encryption:
+ (NSData *)encryptDataWithAESECB:(NSData *)data
key:(NSData *) key
error:(NSError **)error {
size_t outLength;
int cipherLen = (int)(data.length/kAlgorithmBlockSize + 1)*kAlgorithmBlockSize;
NSMutableData *cipherData = [NSMutableData dataWithLength:cipherLen];
NSData *newData = [self addPaddingBeforeEncryptWithAESECB:data];
CCCryptorStatus result = CCCrypt(kCCEncrypt, // operation
kAlgorithm, // Algorithm
kCCOptionECBMode, // Mode
key.bytes, // key
key.length, // keylength
0,// iv
newData.bytes, // dataIn
newData.length, // dataInLength,
cipherData.mutableBytes, // dataOut
cipherData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result == kCCSuccess) {
cipherData.length = outLength;
}else {
if (error) {
*error = [NSError errorWithDomain:kRNCryptManagerErrorDomain code:result userInfo:nil];
}
return nil;
}
return cipherData;
}
What's next?
You have to strip off the extra bytes before AES ECB decryption.
来源:https://stackoverflow.com/questions/35921254/aes-ecb-ios-encrypt