英文:
CCCrypto decrypt: exactly one block less
问题
我正在尝试解密由golang脚本加密的字符串。加密方式是CBC,密钥长度为256位。16字节长的IV包含在密文的开头,正如golang文档建议的那样。除了objc代码总是丢失最后一个块之外,一切都正常。例如,当我期望返回80字节时,只得到64字节,期望返回128字节时,只得到112字节。有什么建议吗?谢谢!
golang代码
func encrypt(text_s, key_s string) []byte {
text := []byte(text_s)
// 填充文本
n := aes.BlockSize - (len(text) % aes.BlockSize)
log.Println("需要填充:", n)
if n != aes.BlockSize || n != 0 {
text = append([]byte(strings.Repeat(" ", n)), text...)
}
log.Println("要加密的文本:'", string(text), "'")
log.Println("填充后的长度:", len(text))
key := []byte(key_s)[:32]
block, _ := aes.NewCipher(key)
// if err != nil {
// panic(err)
// }
ret := make([]byte, aes.BlockSize+len(text))
iv := ret[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
cbc := cipher.NewCBCEncrypter(block, iv)
cbc.CryptBlocks(ret[aes.BlockSize:], text)
return ret
}
objc代码:
- (NSData *)decrypt:(NSData*)data{
if (!key) {
key = [[_token substringToIndex:32] dataUsingEncoding:NSUTF8StringEncoding];
}
// NSLog(@"decodbase64 :%@",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
// NSString *key = _token;
//
// char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
// bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// BOOL patchNeeded = ([_token length] > kCCKeySizeAES256);
// NSLog(@"need patch? %@", patchNeeded ? @"YES": @"NO");
//
// if (patchNeeded) {
// key = [_token substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
// }
// fetch key data
// [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
// if (patchNeeded) {
// // Previous iOS version than iOS7 set the first char to '- (NSData *)decrypt:(NSData*)data{
if (!key) {
key = [[_token substringToIndex:32] dataUsingEncoding:NSUTF8StringEncoding];
}
// NSLog(@"decodbase64 :%@",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
// NSString *key = _token;
//
// char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
// bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// BOOL patchNeeded = ([_token length] > kCCKeySizeAES256);
// NSLog(@"need patch? %@", patchNeeded ? @"YES": @"NO");
//
// if (patchNeeded) {
// key = [_token substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
// }
// fetch key data
// [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
// if (patchNeeded) {
// // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256
// keyPtr[0] = '\0';
// }
size_t dataLength = [data length] - kCCBlockSizeAES128;
NSData *iv = [data subdataWithRange:NSMakeRange(0, kCCBlockSizeAES128)];
NSData *encrypted = [data subdataWithRange:NSMakeRange(kCCBlockSizeAES128, dataLength)];
//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(dataLength);
NSMutableData *ret = [NSMutableData dataWithLength:dataLength + kCCBlockSizeAES128];
size_t numBytesDecrypted = 0;
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES,
kCCOptionPKCS7Padding,
[key bytes],
kCCKeySizeAES256,
[iv bytes],
[encrypted bytes], dataLength, /* input */
[ret mutableBytes], [ret length], /* output */
&numBytesDecrypted
);
NSLog(@"err: %d", status);
NSLog(@"dataLength: %d, num: %d", (int)dataLength, (int)numBytesDecrypted);
if (status == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return ret;
}
// free(buffer); //free the buffer;
return nil;
}
' if the key was longer than kCCKeySizeAES256
// keyPtr[0] = '- (NSData *)decrypt:(NSData*)data{
if (!key) {
key = [[_token substringToIndex:32] dataUsingEncoding:NSUTF8StringEncoding];
}
// NSLog(@"decodbase64 :%@",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
// NSString *key = _token;
//
// char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
// bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// BOOL patchNeeded = ([_token length] > kCCKeySizeAES256);
// NSLog(@"need patch? %@", patchNeeded ? @"YES": @"NO");
//
// if (patchNeeded) {
// key = [_token substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
// }
// fetch key data
// [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
// if (patchNeeded) {
// // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256
// keyPtr[0] = '\0';
// }
size_t dataLength = [data length] - kCCBlockSizeAES128;
NSData *iv = [data subdataWithRange:NSMakeRange(0, kCCBlockSizeAES128)];
NSData *encrypted = [data subdataWithRange:NSMakeRange(kCCBlockSizeAES128, dataLength)];
//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(dataLength);
NSMutableData *ret = [NSMutableData dataWithLength:dataLength + kCCBlockSizeAES128];
size_t numBytesDecrypted = 0;
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES,
kCCOptionPKCS7Padding,
[key bytes],
kCCKeySizeAES256,
[iv bytes],
[encrypted bytes], dataLength, /* input */
[ret mutableBytes], [ret length], /* output */
&numBytesDecrypted
);
NSLog(@"err: %d", status);
NSLog(@"dataLength: %d, num: %d", (int)dataLength, (int)numBytesDecrypted);
if (status == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return ret;
}
// free(buffer); //free the buffer;
return nil;
}
';
// }
size_t dataLength = [data length] - kCCBlockSizeAES128;
NSData *iv = [data subdataWithRange:NSMakeRange(0, kCCBlockSizeAES128)];
NSData *encrypted = [data subdataWithRange:NSMakeRange(kCCBlockSizeAES128, dataLength)];
//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(dataLength);
NSMutableData *ret = [NSMutableData dataWithLength:dataLength + kCCBlockSizeAES128];
size_t numBytesDecrypted = 0;
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES,
kCCOptionPKCS7Padding,
[key bytes],
kCCKeySizeAES256,
[iv bytes],
[encrypted bytes], dataLength, /* input */
[ret mutableBytes], [ret length], /* output */
&numBytesDecrypted
);
NSLog(@"err: %d", status);
NSLog(@"dataLength: %d, num: %d", (int)dataLength, (int)numBytesDecrypted);
if (status == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return ret;
}
// free(buffer); //free the buffer;
return nil;
}
英文:
I'm trying to decrypt string encrypted by golang script. The encryption is CBC, key size 256. 16 bytes long iv is include at the beginning of ciphered text, as golang doc suggested. Everything works fine except the objc codes always lost the last block. e.g. when I expect 80 bytes return but only get 64, expect 128 but get 112. any advice? thanks!
golang code
func encrypt(text_s, key_s string) byte[] {
text := []byte(text_s)
// padding text
n := aes.BlockSize - (len(text) % aes.BlockSize)
log.Println("Need to pad:", n)
if n != aes.BlockSize || n != 0 {
text = append([]byte(strings.Repeat(" ", n)), text...)
}
log.Println("to encrypt:'", string(text), "'")
log.Println("padded length:", len(text))
key := []byte(key_s)[:32]
block, _ := aes.NewCipher(key)
// if err != nil {
// panic(err)
// }
ret := make([]byte, aes.BlockSize + len(text))
iv := ret[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
cbc := cipher.NewCBCEncrypter(block, iv)
cbc.CryptBlocks(ret[aes.BlockSize:], text)
return ret
}
objc codes:
- (NSData *)decrypt:(NSData*)data{
if (!key) {
key = [[_token substringToIndex:32] dataUsingEncoding:NSUTF8StringEncoding];
}
// NSLog(@"decodbase64 :%@",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
// NSString *key = _token;
//
// char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
// bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// BOOL patchNeeded = ([_token length] > kCCKeySizeAES256);
// NSLog(@"need patch? %@", patchNeeded ? @"YES": @"NO");
//
// if (patchNeeded) {
// key = [_token substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
// }
// fetch key data
// [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
// if (patchNeeded) {
// // Previous iOS version than iOS7 set the first char to ' - (NSData *)decrypt:(NSData*)data{
if (!key) {
key = [[_token substringToIndex:32] dataUsingEncoding:NSUTF8StringEncoding];
}
// NSLog(@"decodbase64 :%@",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
// NSString *key = _token;
//
// char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
// bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// BOOL patchNeeded = ([_token length] > kCCKeySizeAES256);
// NSLog(@"need patch? %@", patchNeeded ? @"YES": @"NO");
//
// if (patchNeeded) {
// key = [_token substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
// }
// fetch key data
// [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
// if (patchNeeded) {
// // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256
// keyPtr[0] = '\0';
// }
size_t dataLength = [data length] - kCCBlockSizeAES128;
NSData *iv = [data subdataWithRange:NSMakeRange(0, kCCBlockSizeAES128)];
NSData *encrypted = [data subdataWithRange:NSMakeRange(kCCBlockSizeAES128, dataLength)];
//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(dataLength);
NSMutableData *ret = [NSMutableData dataWithLength:dataLength + kCCBlockSizeAES128];
size_t numBytesDecrypted = 0;
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES,
kCCOptionPKCS7Padding,
[key bytes],
kCCKeySizeAES256,
[iv bytes],
[encrypted bytes], dataLength, /* input */
[ret mutableBytes], [ret length], /* output */
&numBytesDecrypted
);
NSLog(@"err: %d", status);
NSLog(@"dataLength: %d, num: %d", (int)dataLength, (int)numBytesDecrypted);
if (status == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return ret;
}
// free(buffer); //free the buffer;
return nil;
}
' if the key was longer than kCCKeySizeAES256
// keyPtr[0] = ' - (NSData *)decrypt:(NSData*)data{
if (!key) {
key = [[_token substringToIndex:32] dataUsingEncoding:NSUTF8StringEncoding];
}
// NSLog(@"decodbase64 :%@",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
// NSString *key = _token;
//
// char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
// bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// BOOL patchNeeded = ([_token length] > kCCKeySizeAES256);
// NSLog(@"need patch? %@", patchNeeded ? @"YES": @"NO");
//
// if (patchNeeded) {
// key = [_token substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
// }
// fetch key data
// [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding];
// if (patchNeeded) {
// // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256
// keyPtr[0] = '\0';
// }
size_t dataLength = [data length] - kCCBlockSizeAES128;
NSData *iv = [data subdataWithRange:NSMakeRange(0, kCCBlockSizeAES128)];
NSData *encrypted = [data subdataWithRange:NSMakeRange(kCCBlockSizeAES128, dataLength)];
//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(dataLength);
NSMutableData *ret = [NSMutableData dataWithLength:dataLength + kCCBlockSizeAES128];
size_t numBytesDecrypted = 0;
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES,
kCCOptionPKCS7Padding,
[key bytes],
kCCKeySizeAES256,
[iv bytes],
[encrypted bytes], dataLength, /* input */
[ret mutableBytes], [ret length], /* output */
&numBytesDecrypted
);
NSLog(@"err: %d", status);
NSLog(@"dataLength: %d, num: %d", (int)dataLength, (int)numBytesDecrypted);
if (status == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return ret;
}
// free(buffer); //free the buffer;
return nil;
}
';
// }
size_t dataLength = [data length] - kCCBlockSizeAES128;
NSData *iv = [data subdataWithRange:NSMakeRange(0, kCCBlockSizeAES128)];
NSData *encrypted = [data subdataWithRange:NSMakeRange(kCCBlockSizeAES128, dataLength)];
//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(dataLength);
NSMutableData *ret = [NSMutableData dataWithLength:dataLength + kCCBlockSizeAES128];
size_t numBytesDecrypted = 0;
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES,
kCCOptionPKCS7Padding,
[key bytes],
kCCKeySizeAES256,
[iv bytes],
[encrypted bytes], dataLength, /* input */
[ret mutableBytes], [ret length], /* output */
&numBytesDecrypted
);
NSLog(@"err: %d", status);
NSLog(@"dataLength: %d, num: %d", (int)dataLength, (int)numBytesDecrypted);
if (status == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return ret;
}
// free(buffer); //free the buffer;
return nil;
}
答案1
得分: 0
问题出在解密选项上:
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES,
0, // 将其改为0可以解决问题
[key bytes],
kCCKeySizeAES256,
[iv bytes],
[encrypted bytes], dataLength, /* 输入 */
[ret mutableBytes], [ret length], /* 输出 */
&numBytesDecrypted
);
英文:
it turns out the problem is with the decryption option:
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES,
0, // change to 0 solve the problem
[key bytes],
kCCKeySizeAES256,
[iv bytes],
[encrypted bytes], dataLength, /* input */
[ret mutableBytes], [ret length], /* output */
&numBytesDecrypted
);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论