2012-04-23 4 views
3

나는 AES 암호화하고 암호 해독에 대한 시나리오를 제외하고 매우 잘 작동 http://pastie.org/pastes/297563/text아이폰 : 암호 해독 오류 "암호 용의 ccStatus와 *****는 == -4301"

에서 암호 해독 샘플을 발견했다. 긴 문자열 ([email protected])을 가진 사용자 이메일 문자열을 암호화 할 때 암호화 및 복호화에 문제가 없습니다. 암호화 후 plist 파일에 저장 한 다음 암호 해독을 위해 나중에 읽습니다. 그러나 짧은 문자열 (예 : [email protected])이있는 전자 메일 문자열을 암호화하면 암호화가 잘되지만 문자열을 해독하여 레이블에 넣으려고하면 암호 해독이 과 같이 나타납니다

UDPATE "-4301 암호 용 ccStatus의 ==에 문제"나는 그렇지 않으면 항상 잘 작동이 암호 해독 문제는 문자열 길이가 "16"인 경우에만 일어나는 발견했다. 어떤 도움을 주시겠습니까?

아래 코드를 찾으십시오. 이것은 암호화 및 암호 해독을위한 코드입니다.

import "CryptoHelper.h" 

#define LOGGING_FACILITY(X, Y) \ 
if(!(X)) {   \ 
    NSLog(Y);  \ 
}     

#define LOGGING_FACILITY1(X, Y, Z) \ 
if(!(X)) {    \ 
NSLog(Y, Z);  \ 
} 

@interface CryptoHelper(Private) 
- (NSData *)doCipher:(NSData *)plainText key:(NSData *)theSymmetricKey context:(CCOperation)encryptOrDecrypt padding:(CCOptions *)pkcs7; 
- (NSString *)base64EncodeData:(NSData*)dataToConvert; 
- (NSData*)base64DecodeString:(NSString *)string; 
@end 
@implementation CryptoHelper 

static CryptoHelper *MyCryptoHelper = nil; 

const uint8_t kKeyBytes[] = "abcdefgh"; // Must be 16 bytes 
static CCOptions pad = 0; 
static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/"; 

- (NSString*)encryptString:(NSString*)string 
{ 
    NSRange fullRange; 
    fullRange.length = [string length]; 
    fullRange.location = 0; 

    uint8_t buffer[[string length]]; 

    [string getBytes:&buffer maxLength:[string length] usedLength:NULL encoding:NSUTF8StringEncoding options:0 range:fullRange remainingRange:NULL]; 

    NSData *plainText = [NSData dataWithBytes:buffer length:[string length]]; 

    NSData *encryptedResponse = [self doCipher:plainText key:symmetricKey context:kCCEncrypt padding:&pad]; 

    return [self base64EncodeData:encryptedResponse]; 
} 

- (NSString*)decryptString:(NSString*)string 
{ 
    NSLog(@"string: %@", string); 

    NSData *decryptedResponse = [self doCipher:[self base64DecodeString:string] key:symmetricKey context:kCCDecrypt padding:&pad]; 

    NSString *result = [NSString stringWithFormat:@"decryptedResponse: %@", decryptedResponse]; 
    NSLog(@"decryptedResponse: %@", result); 

    return [NSString stringWithCString:[decryptedResponse bytes] length:[decryptedResponse length]]; 
} 

- (NSData *)doCipher:(NSData *)plainText key:(NSData *)theSymmetricKey context:(CCOperation)encryptOrDecrypt padding:(CCOptions *)pkcs7 
{ 
    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)); 

    LOGGING_FACILITY(plainText != nil, @"PlainText object cannot be nil."); 
    LOGGING_FACILITY(theSymmetricKey != nil, @"Symmetric key object cannot be nil."); 
    LOGGING_FACILITY(pkcs7 != NULL, @"CCOptions * pkcs7 cannot be NULL."); 
    LOGGING_FACILITY([theSymmetricKey length] == kCCKeySizeAES128, @"Disjoint choices for key size."); 

    plainTextBufferSize = [plainText length]; 

    LOGGING_FACILITY(plainTextBufferSize > 0, @"Empty plaintext passed in."); 

    // We don't want to toss padding on if we don't need to 
    if(encryptOrDecrypt == kCCEncrypt) 
    { 
     if(*pkcs7 != kCCOptionECBMode) 
     { 
      if((plainTextBufferSize % kCCBlockSizeAES128) == 0) 
      { 
       *pkcs7 = 0x0000; 
      } 
      else 
      { 
       *pkcs7 = kCCOptionPKCS7Padding; 
      } 
     } 
    } 
    else if(encryptOrDecrypt != kCCDecrypt) 
    { 
     LOGGING_FACILITY1(0, @"Invalid CCOperation parameter [%d] for cipher context.", *pkcs7); 
    } 

    // Create and Initialize the crypto reference. 
    ccStatus = CCCryptorCreate(encryptOrDecrypt, 
           kCCAlgorithmAES128, 
           *pkcs7, 
           (const void *)[theSymmetricKey bytes], 
           kCCKeySizeAES128, 
           (const void *)iv, 
           &thisEncipher 
           ); 

    LOGGING_FACILITY1(ccStatus == kCCSuccess, @"Problem creating the context, ccStatus == %d.", ccStatus); 

    // 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 *) [plainText bytes], 
           plainTextBufferSize, 
           ptr, 
           remainingBytes, 
           &movedBytes 
           ); 

    LOGGING_FACILITY1(ccStatus == kCCSuccess, @"Problem with CCCryptorUpdate, ccStatus == %d.", ccStatus); 

    // Handle book keeping. 
    ptr += movedBytes; 
    remainingBytes -= movedBytes; 
    totalBytesWritten += movedBytes; 

    // Finalize everything to the output buffer. 
    ccStatus = CCCryptorFinal( thisEncipher, 
           ptr, 
           remainingBytes, 
           &movedBytes 
          ); 

    totalBytesWritten += movedBytes; 

    if(thisEncipher) 
    { 
     (void) CCCryptorRelease(thisEncipher); 
     thisEncipher = NULL; 
    } 

    LOGGING_FACILITY1(ccStatus == kCCSuccess, @"Problem with encipherment ccStatus == %d", ccStatus); 

    cipherOrPlainText = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)totalBytesWritten]; 

    if(bufferPtr) free(bufferPtr); 

    return cipherOrPlainText; 


} 

#pragma mark - 
#pragma mark Base64 Encode/Decoder 
- (NSString *)base64EncodeData:(NSData*)dataToConvert 
{ 
    if ([dataToConvert length] == 0) 
     return @""; 

    char *characters = malloc((([dataToConvert length] + 2)/3) * 4); 
    if (characters == NULL) 
     return nil; 

    NSUInteger length = 0; 

    NSUInteger i = 0; 
    while (i < [dataToConvert length]) 
    { 
     char buffer[3] = {0,0,0}; 
     short bufferLength = 0; 
     while (bufferLength < 3 && i < [dataToConvert length]) 
      buffer[bufferLength++] = ((char *)[dataToConvert bytes])[i++]; 

     // Encode the bytes in the buffer to four characters, including padding "=" characters if necessary. 
     characters[length++] = encodingTable[(buffer[0] & 0xFC) >> 2]; 
     characters[length++] = encodingTable[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)]; 
     if (bufferLength > 1) 
      characters[length++] = encodingTable[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)]; 
     else characters[length++] = '='; 
     if (bufferLength > 2) 
      characters[length++] = encodingTable[buffer[2] & 0x3F]; 
     else characters[length++] = '=';  
    } 

    return [[[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES] autorelease]; 
} 

- (NSData*)base64DecodeString:(NSString *)string 
{ 
    if (string == nil) 
     [NSException raise:NSInvalidArgumentException format:nil]; 
    if ([string length] == 0) 
     return [NSData data]; 

    static char *decodingTable = NULL; 
    if (decodingTable == NULL) 
    { 
     decodingTable = malloc(256); 
     if (decodingTable == NULL) 
      return nil; 
     memset(decodingTable, CHAR_MAX, 256); 
     NSUInteger i; 
     for (i = 0; i < 64; i++) 
      decodingTable[(short)encodingTable[i]] = i; 
    } 

    const char *characters = [string cStringUsingEncoding:NSASCIIStringEncoding]; 
    if (characters == NULL)  // Not an ASCII string! 
     return nil; 
    char *bytes = malloc((([string length] + 3)/4) * 3); 
    if (bytes == NULL) 
     return nil; 
    NSUInteger length = 0; 

    NSUInteger i = 0; 
    while (YES) 
    { 
     char buffer[4]; 
     short bufferLength; 
     for (bufferLength = 0; bufferLength < 4; i++) 
     { 
      if (characters[i] == '\0') 
       break; 
      if (isspace(characters[i]) || characters[i] == '=') 
       continue; 
      buffer[bufferLength] = decodingTable[(short)characters[i]]; 
      if (buffer[bufferLength++] == CHAR_MAX)  // Illegal character! 
      { 
       free(bytes); 
       return nil; 
      } 
     } 

     if (bufferLength == 0) 
      break; 
     if (bufferLength == 1)  // At least two characters are needed to produce one byte! 
     { 
      free(bytes); 
      return nil; 
     } 

     // Decode the characters in the buffer to bytes. 
     bytes[length++] = (buffer[0] << 2) | (buffer[1] >> 4); 
     if (bufferLength > 2) 
      bytes[length++] = (buffer[1] << 4) | (buffer[2] >> 2); 
     if (bufferLength > 3) 
      bytes[length++] = (buffer[2] << 6) | buffer[3]; 
    } 

    realloc(bytes, length); 

    return [NSData dataWithBytesNoCopy:bytes length:length]; 
} 

#pragma mark - 
#pragma mark Singleton methods 
- (id)init 
{ 
    if(self = [super init]) 
    { 
     symmetricKey = [[NSData dataWithBytes:kKeyBytes length:sizeof(kKeyBytes)] retain]; 
    } 
    return self; 
} 

+ (CryptoHelper*)sharedInstance 
{ 
    @synchronized(self) 
    { 
     if (MyCryptoHelper == nil) 
     { 
      [[self alloc] init]; 
     } 
    } 
    return MyCryptoHelper; 
} 

+ (id)allocWithZone:(NSZone *)zone 
{ 
    @synchronized(self) 
    { 
     if (MyCryptoHelper == nil) 
     { 
      MyCryptoHelper = [super allocWithZone:zone]; 
      return MyCryptoHelper; // assignment and return on first allocation 
     } 
    } 
    return nil; // on subsequent allocation attempts return nil 
} 

- (id)copyWithZone:(NSZone *)zone 
{ 
    return self; 
} 

- (id)retain 
{ 
    return self; 
} 

- (unsigned)retainCount 
{ 
    return UINT_MAX; // denotes an object that cannot be released 
} 

- (void)release 
{ 
    //do nothing 
} 

- (id)autorelease 
{ 
    return self; 
} 

@end 

아래의 코드는

-(NSString *) getUsername 
    { 
     NSString *usernameString = NULL; 

     // Data.plist code 
     // get paths from root direcory 
     NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES); 
     // get documents path 
     NSString *documentsPath = [paths objectAtIndex:0]; 
     // get the path to our Data/plist file 
     NSString *plistPath = [documentsPath stringByAppendingPathComponent:LOGIN_PLIST]; 

     // check to see if Data.plist exists in documents 
     if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath]) 
     { 
      // if not in documents, get property list from main bundle 
      plistPath = [[NSBundle mainBundle] pathForResource:@"LoginInfo" ofType:@"plist"]; 
     } 

     // read property list into memory as an NSData object 
     NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath]; 
     NSString *errorDesc = nil; 
     NSPropertyListFormat format; 
     // convert static property liost into dictionary object 
     NSDictionary *temp = (NSDictionary *)[NSPropertyListSerialization propertyListFromData:plistXML mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&errorDesc]; 
     if (!temp) 
     { 
      //NSLog(@"Error reading plist: %@, format: %lu", errorDesc, format); 
     } 
     else 
     { 
      NSString *nameStr=[temp objectForKey:@"Username"];  

      NSLog(@"nameStr: %@",nameStr); 

      // do AES128 decryption 
      CryptoHelper *pCrypto = [CryptoHelper sharedInstance]; 
      usernameString = [pCrypto decryptString:nameStr]; 
// usernameString becomes empty after when encryption and trying to decrypt. 
      NSLog(@"usernameString: %@: usernameString length: %ld", usernameString, [usernameString length]); 

     } 

     return usernameString; 
    } 

답변

1

귀하의 코드는 애플의 'CryptoExercise' example에서 SecKeyWrapper 클래스를 기반으로, 위의 호출이다. doCipher 메서드를 사용할 때 동일한 오류 메시지가 나타났습니다.

'-4301'는이 경우 입력 CCryptorStatus 값을 반환 의 통화 CCCryptoFinal, 후 ccStatus 변수의 값이다. 그것은 크기 CCCryptorGetOutputLength 통해 판단 때문에

enum { 
    kCCSuccess   = 0, 
    kCCParamError  = -4300, 
    kCCBufferTooSmall = -4301, 
    kCCMemoryFailure = -4302, 
    kCCAlignmentError = -4303, 
    kCCDecodeError  = -4304, 
    kCCUnimplemented = -4305 
}; 

그래서 든 doCipher 방법에서 생성 된 버퍼는 단지 의 문서로, 홀수 인 너무 작

다음과 같다 : 이것은 CommonCryptor.h에 정의 된 CCCryptorFinal는 제안 :

@result kCCBufferTooSmall indicates insufficent space in the dataOut buffer. 
     The caller can use CCCryptorGetOutputLength() to determine the required 
     output buffer size in this case. The operation can be retried; no state is 
     lost when this is returned. 

내가 애플 예를에서 SecKeyWrapper 클래스 버그 무료 아니라는 것을 직감을 가지고있다. 문제를 해결할 수 있는지 또는 iPhone에서 AES 암호화를 수행 할 다른 방법을 찾을 수 있는지 확인합니다. Rob Napier와 Mugunth Kumar의 책 'iOS 5 programming - Pushing the limits'에 설명과 예제 코드가 있습니다. 또한 저자는 developer.apple.com에서 이용할 수있는 두 개의 WWDC 세션을 권장합니다. WWDC 2010

  • , "세션 (204) : 보안 응용 프로그램 만들기"
  • WWDC 2011, "세션 (208) : 보안의 iOS 응용 프로그램"
  • 편집

:

난 그냥 오류를 발견 . doCipher 메서드 내에 있습니다.다음 줄

// We don't want to toss padding on if we don't need to 
    if(encryptOrDecrypt == kCCEncrypt) 
    { 
     if(*pkcs7 != kCCOptionECBMode) 
     { 
      if((plainTextBufferSize % kCCBlockSizeAES128) == 0) 
      { 
       *pkcs7 = 0x0000; 
      } 
      else 
      { 
       *pkcs7 = kCCOptionPKCS7Padding; 
      } 
     } 
    } 
    else if(encryptOrDecrypt != kCCDecrypt) 
    { 
     LOGGING_FACILITY1(0, @"Invalid CCOperation parameter [%d] for cipher context.", *pkcs7); 
    } 

: Ortwin 아래 지적

// check for valid context parameter 
if (encryptOrDecrypt != kCCEncrypt && encryptOrDecrypt != kCCDecrypt) { 
    LOGGING_FACILITY1(0, @"Invalid CCOperation parameter [%d] for cipher context.", encryptOrDecrypt); 
} 

, 당신은 또한 항상 kCCOptionPKCS7Padding로 후속 CCCryptorCreate 호출에서 세 번째 매개 변수를 교체해야 : 간단하게 다음 줄을 대체

// Create and Initialize the crypto reference. 
ccStatus = CCCryptorCreate(encryptOrDecrypt, 
          kCCAlgorithmAES128, 
          kCCOptionPKCS7Padding, 
          (const void *)[theSymmetricKey bytes], 
          kCCKeySizeAES128, 
          (const void *)iv, 
          &thisEncipher 
          ); 
+0

그래서 오류가 발생할 수 있으므로 기본적으로 완전한 첫 번째 경우를 제거합니다. 첫 번째 if-case가 제거 되었기 때문에 else-if-case가 간단한 if-case로 바뀌므로 이전 else 부분 (예 : encryptOrDecrypt! = kCCEncrypt)도 유지해야합니다. – Tafkadasoh

+0

당신의 솔루션이 나를 위해 작동하지 않습니다. 34 바이트 길이의 문자열을 암호화하고 다시 해독하면 결과는 32 바이트 길이가되고 마지막 2 문자는 잘립니다. –

0

은 내가

를 교체 할 때 나를 위해 작동하는 것을 발견

// We don't want to toss padding on if we don't need to 
if (encryptOrDecrypt != kCCEncrypt && encryptOrDecrypt != kCCDecrypt) { 
    LOGGING_FACILITY1(0, @"Invalid CCOperation parameter [%d] for cipher context.", *pkcs7); 
} 

// Create and Initialize the crypto reference. 
ccStatus = CCCryptorCreate(encryptOrDecrypt, 
          kCCAlgorithmAES128, 
          kCCOptionPKCS7Padding, 
          (const void *)[theSymmetricKey bytes], 
          kCCKeySizeAES128, 
          (const void *)iv, 
          &thisEncipher 
          ); 

에 의해3210

// We don't want to toss padding on if we don't need to 
if(encryptOrDecrypt == kCCEncrypt) 
{ 
    if(*pkcs7 != kCCOptionECBMode) 
    { 
     if((plainTextBufferSize % kCCBlockSizeAES128) == 0) 
     { 
      *pkcs7 = 0x0000; 
     } 
     else 
     { 
      *pkcs7 = kCCOptionPKCS7Padding; 
     } 
    } 
} 
else if(encryptOrDecrypt != kCCDecrypt) 
{ 
    LOGGING_FACILITY1(0, @"Invalid CCOperation parameter [%d] for cipher context.", *pkcs7); 
} 

// Create and Initialize the crypto reference. 
ccStatus = CCCryptorCreate(encryptOrDecrypt, 
          kCCAlgorithmAES128, 
          *pkcs7, 
          (const void *)[theSymmetricKey bytes], 
          kCCKeySizeAES128, 
          (const void *)iv, 
          &thisEncipher 
          ); 

는 기본적으로, 나는 항상 상관없이 암호화 또는 암호 해독 여부와 상관없이 텍스트 길이 CCCryptorCreate에 대한 kCCOptionPKCS7Padding 옵션을 설정합니다.

제 경우가 제한되어 있으며 모든 상황에서이 테스트가 작동하는지 테스트하지 않았습니다. 보장이 없습니다!

+0

솔루션의 50 %를 신용 해 주셔서 감사합니다 ... 아닙니다. – Tafkadasoh

+0

당신의 솔루션은 나의 것과 반대입니다. 항상 패딩을 사용하는 반면 완전히 패딩은 제거합니다. 두 가지 솔루션은 Apple 샘플 코드에서 파생됩니다. 내가 너를 위해 신용 해야할지 모르겠다. 또한, 업 워프가 작동 솔루션 (귀하의 솔루션은 나를 위해 작동하지 않았다.)에 대해 주어져야한다. 누군가가 응답에 넣은 시간을 인식하지 못한다. –