Tri*_*ert 2 security encryption cocoa nsstring
我有一个基本的笔记应用程序,我想让用户有加密或安全的笔记.我有一个用户界面,但是现在,我似乎无法加密.它要么返回一堆垃圾,要么根本没有.这是我用来/解密的:
- (BOOL) encryptWithAES128Key: (NSString *) key {
// 'key' should be 16 bytes for AES128, will be null-padded otherwise
char * keyPtr[kCCKeySizeAES128+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];
// encrypts in-place, since this is a mutable data object
size_t numBytesEncrypted = 0;
CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128 , kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
[self mutableBytes], [self length], /* input */
[self mutableBytes], [self length] + kCCBlockSizeAES128, /* output */
&numBytesEncrypted);
return (result == kCCSuccess);
}
- (NSMutableData *) decryptWithAES128Key: (NSString *) key {
// 'key' should be 16 bytes for AES128, will be null-padded otherwise
char * keyPtr[kCCKeySizeAES128+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];
// encrypts in-place, since this is a mutable data object
size_t bufferSize = [self length] + kCCBlockSizeAES128;
void* buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus result = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
[self bytes], [self length], /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if(result == kCCSuccess || result == kCCParamError) {
return [[NSMutableData dataWithBytesNoCopy:buffer length:numBytesEncrypted] retain];
}
return nil;
}
Run Code Online (Sandbox Code Playgroud)
有谁知道为什么这可能会出错?
编辑1: 我修改了我的en/decryption代码是一样的.以下是它现在的样子:
- (BOOL) encryptWithAES128Key: (NSString *) key {
CCCryptorStatus ccStatus = kCCSuccess;
// Symmetric crypto reference.
CCCryptorRef thisEncipher = NULL;
// Cipher Text container.
NSData * cipherOrPlainText = nil;
// Pointer to output buffer.
uint8_t * bufferPtr = NULL;
// Total size of the buffer.
size_t bufferPtrSize = 0;
// Remaining bytes to be performed on.
size_t remainingBytes = 0;
// Number of bytes moved to buffer.
size_t movedBytes = 0;
// Length of plainText buffer.
size_t plainTextBufferSize = 0;
// Placeholder for total written.
size_t totalBytesWritten = 0;
// A friendly helper pointer.
uint8_t * ptr;
// Initialization vector; dummy in this case 0's.
uint8_t iv[kCCBlockSizeAES128];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
plainTextBufferSize = [self length];
ccStatus = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, (const void *)[key UTF8String], kCCKeySizeAES128, (const void *)iv, &thisEncipher);
// Calculate byte block alignment for all calls through to and including final.
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);
// Allocate buffer.
bufferPtr = [self mutableBytes];
// Zero out buffer.
//memset((void *)bufferPtr, 0x0, bufferPtrSize);
// Initialize some necessary book keeping.
ptr = bufferPtr;
// Set up initial size.
remainingBytes = bufferPtrSize;
// Actually perform the encryption or decryption.
ccStatus = CCCryptorUpdate(thisEncipher, (const void *) [self bytes], plainTextBufferSize, ptr, remainingBytes, &movedBytes);
ptr += movedBytes;
remainingBytes -= movedBytes;
totalBytesWritten += movedBytes;
// Finalize everything to the output buffer.
ccStatus = CCCryptorFinal(thisEncipher, ptr, remainingBytes, &movedBytes);
cipherOrPlainText = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)totalBytesWritten];
NSLog(@"data: %@", cipherOrPlainText);
NSLog(@"buffer: %s", bufferPtr);
CCCryptorRelease(thisEncipher);
thisEncipher = NULL;
if(bufferPtr) free(bufferPtr);
}
- (NSMutableData *) decryptWithAES128Key: (NSString *) key {
CCCryptorStatus ccStatus = kCCSuccess;
// Symmetric crypto reference.
CCCryptorRef thisEncipher = NULL;
// Cipher Text container.
NSData * cipherOrPlainText = nil;
// Pointer to output buffer.
uint8_t * bufferPtr = NULL;
// Total size of the buffer.
size_t bufferPtrSize = 0;
// Remaining bytes to be performed on.
size_t remainingBytes = 0;
// Number of bytes moved to buffer.
size_t movedBytes = 0;
// Length of plainText buffer.
size_t plainTextBufferSize = 0;
// Placeholder for total written.
size_t totalBytesWritten = 0;
// A friendly helper pointer.
uint8_t * ptr;
// Initialization vector; dummy in this case 0's.
uint8_t iv[kCCBlockSizeAES128];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
plainTextBufferSize = [self length];
ccStatus = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, (const void *)[key UTF8String], kCCKeySizeAES128, (const void *)iv, &thisEncipher);
// Calculate byte block alignment for all calls through to and including final.
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);
// Allocate buffer.
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t) );
// Zero out buffer.
memset((void *)bufferPtr, 0x0, bufferPtrSize);
// Initialize some necessary book keeping.
ptr = bufferPtr;
// Set up initial size.
remainingBytes = bufferPtrSize;
// Actually perform the encryption or decryption.
ccStatus = CCCryptorUpdate(thisEncipher, (const void *) [self bytes], plainTextBufferSize, ptr, remainingBytes, &movedBytes);
ptr += movedBytes;
remainingBytes -= movedBytes;
totalBytesWritten += movedBytes;
// Finalize everything to the output buffer.
ccStatus = CCCryptorFinal(thisEncipher, ptr, remainingBytes, &movedBytes);
cipherOrPlainText = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)totalBytesWritten];
NSLog(@"data: %@", cipherOrPlainText);
NSLog(@"buffer: %s", bufferPtr);
CCCryptorRelease(thisEncipher);
thisEncipher = NULL;
if(bufferPtr) free(bufferPtr);
return [NSMutableData dataWithData:cipherOrPlainText];
}
Run Code Online (Sandbox Code Playgroud)
这段代码有点用.如果我使用密码'1234567890123456'加密此字符串:
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>dict</key>
<dict>
<key>device</key>
<string>Tristan's Magical Macbook of Death</string>
<key>text</key>
<string>e1xydGYxXGFuc2lcYW5zaWNwZzEyNTJcY29jb2FydGYxMDM4XGNvY29hc3VicnRm
MzYwCntcZm9udHRibFxmMFxmc3dpc3NcZmNoYXJzZXQwIEhlbHZldGljYTt9Cntc
Y29sb3J0Ymw7XHJlZDI1NVxncmVlbjI1NVxibHVlMjU1O30KXHBhcmRcdHg1NjBc
dHgxMTIwXHR4MTY4MFx0eDIyNDBcdHgyODAwXHR4MzM2MFx0eDM5MjBcdHg0NDgw
XHR4NTA0MFx0eDU2MDBcdHg2MTYwXHR4NjcyMFxxbFxxbmF0dXJhbFxwYXJkaXJu
YXR1cmFsCgpcZjBcZnMyNCBcY2YwIFx1bCBcdWxjMCBCTEFILn0=
</string>
<key>title</key>
<string>Welcome to Notepaddy!</string>
<key>uuid</key>
<string>5yvghz9n4ukgefnbx0qa2xne3nxeebcmcvpci9j5lwpncul1asftdayjv8a</string>
</dict>
<key>text</key>
<string>e1xydGYxXGFuc2lcYW5zaWNwZzEyNTJcY29jb2FydGYxMDM4XGNvY29hc3VicnRm
MzYwCntcZm9udHRibFxmMFxmc3dpc3NcZmNoYXJzZXQwIEhlbHZldGljYTt9Cntc
Y29sb3J0Ymw7XHJlZDI1NVxncmVlbjI1NVxibHVlMjU1O30KXHBhcmRcdHg1NjBc
dHgxMTIwXHR4MTY4MFx0eDIyNDBcdHgyODAwXHR4MzM2MFx0eDM5MjBcdHg0NDgw
XHR4NTA0MFx0eDU2MDBcdHg2MTYwXHR4NjcyMFxxbFxxbmF0dXJhbFxwYXJkaXJu
YXR1cmFsCgpcZjBcZnMyNCBcY2YwIFx1bCBcdWxjMCBCTEFILn0=
</string>
<key>title</key>
<string>Welcome to Notepaddy!</string>
<key>uuid</key>
<string>5yvghz9n4ukgefnbx0qa2xne3nxeebcmcvpci9j5lwpncul1asftdayjv8a</string>
</dict>
</plist>
Run Code Online (Sandbox Code Playgroud)
我得到了相同的文字,但整个文本</plist>都丢失了,而且</dict>被切断了.解密和打印结果字符串时,使用密码"0987654321123456"或任何其他密码加密时会给我完全垃圾,或者在复制到密码字段时与上面相同.
两个版本都有相同的问题:您告诉CommonCrypto写入缓冲区的末尾,然后忽略结果.
第一个版本:
[self mutableBytes], [self length] + kCCBlockSizeAES128, /* output */
Run Code Online (Sandbox Code Playgroud)
第二个版本:
// Calculate byte block alignment for all calls through to and including final.
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);
// Allocate buffer.
bufferPtr = [self mutableBytes];
Run Code Online (Sandbox Code Playgroud)
那是不对的.你没有分配任何东西.你告诉它把bufferPtrSize字节写入一个大小的缓冲区[self length]!
你想做更像这样的事情(如果你真的想要就地加密):
// Calculate byte block alignment for all calls through to and including final.
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);
// Increase my size if necessary:
if (bufferPtrSize > self.length) {
self.length = bufferPtrSize;
}
Run Code Online (Sandbox Code Playgroud)
我也不确定为什么加密是就地而解密不是; 如果有的话,后者更容易做到.
您的第二个版本还有其他问题:
if(bufferPtr) free(bufferPtr);(const void *)[key UTF8String], kCCKeySizeAES128额外的加密问题:
附录:
您看到截断结果的原因是因为您返回截断的答案(使用PKCS7填充,加密结果始终大于原始数据).机会(大约255/256)是最后一个密文块被错误地填充(因为你给了CCryptor截断的数据),所以ccStatus说发生了一个错误但是你忽略了这个并且无论如何都返回了结果.这是非常糟糕的做法.(另外,你真的想使用带CBC的MAC来避免填充oracle安全漏洞.)
编辑:
一些似乎工作的代码看起来像这样(完成测试用例):
笔记:
[string dataUsingEncoding:NSUTF8StringEncoding].对于奖励积分,请通过CC_SHA256运行并获取前16个输出字节..
#include <Foundation/Foundation.h>
#include <CommonCrypto/CommonCryptor.h>
#if TARGET_OS_IPHONE
#include <Security/SecRandom.h>
#else
#include <fcntl.h>
#include <unistd.h>
#endif
@interface NSData(AES)
- (NSData*) encryptedDataUsingAESKey: (NSData *) key;
- (NSData*) decryptedDataUsingAESKey: (NSData *) key;
@end
@implementation NSData(AES)
- (NSData*) encryptedDataUsingAESKey: (NSData *) key {
uint8_t iv[kCCBlockSizeAES128];
#if TARGET_OS_IPHONE
if (0 != SecRandomCopyBytes(kSecRandomDefault, sizeof(iv), iv))
{
return nil;
}
#else
{
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) { return nil; }
ssize_t bytesRead;
for (uint8_t * p = iv; (bytesRead = read(fd,p,iv+sizeof(iv)-p)); p += (size_t)bytesRead) {
// 0 means EOF.
if (bytesRead == 0) { close(fd); return nil; }
// -1, EINTR means we got a system call before any data could be read.
// Pretend we read 0 bytes (since we already handled EOF).
if (bytesRead < 0 && errno == EINTR) { bytesRead = 0; }
// Other errors are real errors.
if (bytesRead < 0) { close(fd); return nil; }
}
close(fd);
}
#endif
size_t retSize = 0;
CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[key bytes], [key length],
iv,
[self bytes], [self length],
NULL, 0,
&retSize);
if (result != kCCBufferTooSmall) { return nil; }
// Prefix the data with the IV (the textbook method).
// This requires adding sizeof(iv) in a few places later; oh well.
void * retPtr = malloc(retSize+sizeof(iv));
if (!retPtr) { return nil; }
// Copy the IV.
memcpy(retPtr, iv, sizeof(iv));
result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[key bytes], [key length],
iv,
[self bytes], [self length],
retPtr+sizeof(iv),retSize,
&retSize);
if (result != kCCSuccess) { free(retPtr); return nil; }
NSData * ret = [NSData dataWithBytesNoCopy:retPtr length:retSize+sizeof(iv)];
// Does +[NSData dataWithBytesNoCopy:length:] free if allocation of the NSData fails?
// Assume it does.
if (!ret) { free(retPtr); return nil; }
return ret;
}
- (NSData*) decryptedDataUsingAESKey: (NSData *) key {
const uint8_t * p = [self bytes];
size_t length = [self length];
if (length < kCCBlockSizeAES128) { return nil; }
size_t retSize = 0;
CCCryptorStatus result = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[key bytes], [key length],
p,
p+kCCBlockSizeAES128, length-kCCBlockSizeAES128,
NULL, 0,
&retSize);
if (result != kCCBufferTooSmall) { return nil; }
void * retPtr = malloc(retSize);
if (!retPtr) { return nil; }
result = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[key bytes], [key length],
p,
p+kCCBlockSizeAES128, length-kCCBlockSizeAES128,
retPtr, retSize,
&retSize);
if (result != kCCSuccess) { free(retPtr); return nil; }
NSData * ret = [NSData dataWithBytesNoCopy:retPtr length:retSize];
// Does +[NSData dataWithBytesNoCopy:length:] free if allocation of the NSData fails?
// Assume it does.
if (!ret) { free(retPtr); return nil; }
return ret;
}
@end
void test(NSData * data, NSData * key)
{
NSLog(@"%@, %@", data, key);
NSData * enc = [data encryptedDataUsingAESKey:key];
NSLog(@"%@", enc);
NSData * dec = [enc decryptedDataUsingAESKey:key];
NSLog(@"%@", dec);
NSLog((data == dec || [data isEqual:dec]) ? @"pass" : @"FAIL");
}
int main()
{
#define d(x) [NSData dataWithBytesNoCopy:("" x) length:sizeof("" x)-1 freeWhenDone:0]
[NSAutoreleasePool new];
NSData * key = d("0123456789abcdef");
test([NSData data], key);
test(d(""), key);
test(d("a"), key);
test(d("0123456789abcde"), key);
test(d("0123456789abcdef"), key);
test(d("0123456789abcdef0"), key);
test(d("0123456789abcdef0123456789abcde"), key);
test(d("0123456789abcdef0123456789abcdef"), key);
test(d("0123456789abcdef0123456789abcdef0"), key);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13858 次 |
| 最近记录: |