2015-01-29 6 views
1

AES 128 CBC를 사용하여 데이터를 암호화하는 iOS 앱이 있습니다. 나는 객관적인 - C에서 응용 프로그램 내에서 해당 데이터를 해독 할 수 있으므로 최소한 암호화가 해당 컨텍스트 (일반 암호화)에서 올바르게 작동한다고 알립니다. 문제는이 암호화 된 데이터를 서버로 보내고 PHP를 통해 해독해야한다는 것입니다. 그것이 내가 실패하고있는 곳입니다.AES 128 암호 해독 실패

수동으로 openssl을 사용하여 명령 줄에서 암호화를 수행했습니다. 이 출력을 사용하여이 php 함수로 다시 입력하면 암호를 올바르게 해독 할 수 있으므로 PHP 함수가 올바르게 작동하는지, 적어도 openssl과 관련하여 알 수 있습니다. 그래서, 문제는 openssl과 같은 방식으로 Objective-C에서 암호문을 출력하는 방법입니다 (또는 PHP로 Common Crypto에서 암호문을 해독하는 방법). 즉, 이러한 각 기능은 자체적 인 맥락에서 작동합니다.

<?php 

function jsonEncode ($result, $message) { 
    $arr = array('result' => $result, 'message' => $message); 
    echo json_encode($arr); 
} 


//$ciphertext = base64_decode($_POST['ciphertext']); 
//$iv   = $_POST['iv']; 

// overriding the http post values with values copied in from console output for testing 
$ciphertext = base64_decode('dwb7MWCQUUiVuJLzL2EzYm0NcodwORP47qPhLzaolAk='); 
// openssl on the command line yields ciphertext of 
// 'gRiOXseXTjhpPCiiHgnaQQoal3a9E87Gx3FVpZPtR1I=' which decrypts successfully 
$iv = 'hkPDfznq1t1UpKrW'; 
$key = 'T8ZvJba0HHsmiVSD'; 

//$plaintext = openssl_decrypt($ciphertext, 'aes-128-cbc', $key, false, $iv); 
//jsonEncode('success', $plaintext); 

// this is the line that fails 
$plaintext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext, MCRYPT_MODE_CBC, $iv); 
//$padding = ord($plaintext[strlen($plaintext) - 1]); 
//jsonEncode('success', substr($plaintext, 0, -$padding)); 
jsonEncode('success', $plaintext); 
?> 

편집 : 아래 @Zaph에서 매우 도움이 의견을 바탕으로, 나는 수동으로 패딩을 할 오브젝티브 C에 내 암호화 기능을 다시 작성했습니다. 나는 이것이 정확하다고 생각한다. 그러나 PHP 함수가 반환 될 때 mcrypt_decrypt 함수는 false로 평가됩니다.

- (NSData *)AES128EncryptWithKey:(NSString *)key iv:(NSString *)iv 
{ 
    char keyPtr[kCCKeySizeAES128+1]; 
    bzero(keyPtr, sizeof(keyPtr)); 

    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; 

    char ivPtr[kCCBlockSizeAES128 + 1]; 
    bzero(ivPtr, sizeof(ivPtr)); 
    if (iv) { 
     [iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding]; 
    } 

    NSUInteger dataLength = [self length]; 
    int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128); 
    int newSize = 0; 

    if(diff > 0) { 
     newSize = (int)(dataLength + diff); 
    } 

    // manually add padding to the end of the data array 
    char dataPtr[newSize]; 
    memcpy(dataPtr, [self bytes], [self length]); 
    for(int i = 0; i < diff; i++) { 
     dataPtr[i + dataLength] = diff; 
    } 
    dataPtr[newSize] = '\0'; 

    size_t bufferSize = newSize + kCCBlockSizeAES128; 
    void *buffer = malloc(bufferSize); 

    // print out the padded array for verification 
    NSLog(@"diff: %d new size: %d", diff, newSize); 
    for (int i=0; i<newSize; i++) 
     printf("0x%x ", dataPtr[i]); 

    printf("\n"); 


    size_t numBytesEncrypted = 0; 
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, 
              kCCAlgorithmAES128, 
              0x0000, //No padding 
              keyPtr, 
              kCCKeySizeAES128, 
              ivPtr, 
              dataPtr, 
              sizeof(dataPtr), 
              buffer, 
              bufferSize, 
              &numBytesEncrypted); 

    if(cryptStatus == kCCSuccess) { 
     return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; 
    } 

    return nil; 
} 

목표 C 콘솔 출력 :

diff: 12 new size: 32 
0x65 0x6e 0x63 0x72 0x79 0x70 0x74 0x69 0x6f 0x6e 0x20 0x69 0x73 0x20 0x74 0x72 0x69 0x63 0x6b 0x79 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 
encrypted text: dwb7MWCQUUiVuJLzL2EzYm0NcodwORP47qPhLzaolAk= 

일반 텍스트는 '암호화가 까다 롭다'는 여기에 새로운 목표 C 함수이다.

+0

자신 만의 암호화를 수행하는 이유는 무엇입니까? 당신은 ssl을 사용할 수 있습니다. "자유"를위한 암호화를 제공합니다. –

+1

나는 내 자신의 암호화를하고 있지 않다. Apple Developer Library에서 CommonCrypto를 사용하고 있습니다. – Alex

+0

@MarcB Common Crypto는 Apple의 iOS 용 암호화 라이브러리입니다. OpenSSL은 iOS 용으로 제공되지 않으므로 소스를 가져 와서 쉽게 컴파일 할 수 있어야한다는 의미에서 무료는 아닙니다. – zaph

답변

1

PHP는 kCCOptionPKCS7Padding을 지원하지 않으므로 패딩을 수행하는 방법에 대해 알고 있습니다. 따라서 CCCrypt 이전에 패딩을 제공해야합니다. 또는 PHP 코드에서 PKCS # 7 패딩을 수행하십시오. (BTW : PKCS # 5와 PKCS # 7 패딩은 본질적으로 같습니다.)

첫 번째 블록의 proior 블록이 php에서 해독되는지 확인해야합니다. 그렇지 않은 경우 다른 문제가 있습니다. 여기

내 널 (PHP) 패딩 방법 :

+ (NSData *)phpPadData:(NSData *)data { 
    NSMutableData *newData = [data mutableCopy]; 
    NSUInteger paddLength = kCCBlockSizeAES128 - (data.length % kCCBlockSizeAES128); 
    [newData increaseLengthBy:paddLength]; 

    return [newData copy]; 
} 

내가 "암호화가 까다 롭다"인코딩이를 사용할 때 내가 얻을 : 정확히 내가하면 얻을 같은

 
ciphertextData: 81188e5e c7974e38 693c28a2 1e09da41 a5d64983 e124b73c 36da520a 8198d3e7 
ciphertextBase64: gRiOXseXTjhpPCiiHgnaQaXWSYPhJLc8NtpSCoGY0+c= 

어느 나는 온라인 사이트를 사용한다 : http://aes.online-domain-tools.com (아마도 php mcrypt를 사용하고있다). 이것은 질문의 OpenSSL과 다릅니다.

여기에 내 테스트 코드가 있는데, 문자열을 암호화에서 데이터 인코딩으로/암호화에서 분리합니다. 내가 클래스 이름 테스트에 클래스 메서드를 넣어, 모든 클래스 않습니다.

+ (NSString *)encryptCleartextString:(NSString *)cleartextString keyString:(NSString *)keyString ivString:(NSString *)ivString { 
    NSData *cleartext = [cleartextString dataUsingEncoding:NSUTF8StringEncoding]; 
    NSData *key  = [keyString  dataUsingEncoding:NSUTF8StringEncoding]; 
    NSData *iv  = [ivString  dataUsingEncoding:NSUTF8StringEncoding]; 

    NSData *ciphertext = [Test phpEncryptCleartext:cleartext key:key iv:iv]; 
    NSLog(@"ciphertext: %@", ciphertext); 
    NSString *ciphertextString = [ciphertext base64EncodedStringWithOptions:0]; 
    NSLog(@"ciphertextString: %@", ciphertextString); 

    return ciphertextString; 
} 

+ (NSData *)phpEncryptCleartext:(NSData *)cleartext key:(NSData *)key iv:(NSData *)iv { 
    NSLog(@"phpEncryptCleartext"); 
    NSLog(@"cleartext: %@", cleartext); 
    NSLog(@"key:  %@", key); 
    NSLog(@"iv:  %@", iv); 

    NSData *cleartextPadded = [self phpPadData:cleartext]; 
    NSLog(@"cleartextPadded: %@", cleartextPadded); 

    CCCryptorStatus ccStatus = kCCSuccess; 
    size_t   cryptBytes = 0; // Number of bytes moved to buffer. 
    NSMutableData *ciphertext = [NSMutableData dataWithLength:cleartextPadded.length]; 

    ccStatus = CCCrypt(kCCEncrypt, 
         kCCAlgorithmAES128, 
         0, 
         key.bytes, 
         kCCKeySizeAES128, 
         iv.bytes, 
         cleartextPadded.bytes, 
         cleartextPadded.length, 
         ciphertext.mutableBytes, 
         ciphertext.length, 
         &cryptBytes); 

    if (ccStatus == kCCSuccess) { 
     ciphertext.length = cryptBytes; 
    } 
    else { 
     NSLog(@"kEncryptionError code: %d", ccStatus); // Add error handling 
     ciphertext = nil; 
    } 
    NSLog(@"ciphertext:    %@", ciphertext); 

    return ciphertext; 
} 

// Test code 
NSString *cleartextString = @"encryption is tricky"; 
NSString *ivString = @"hkPDfznq1t1UpKrW"; 
NSString *keyString = @"T8ZvJba0HHsmiVSD"; 

NSString *encryptedTextBase64 = [Test encryptCleartextString:cleartextString keyString:keyString ivString:ivString]; 
NSLog(@"encryptedTextBase64:  %@", encryptedTextBase64); 
+0

확인. 감사. 이것은 어려울 수도있는 것처럼 들립니다. – Alex

+0

너무 어렵지 않고 마지막 블록에 적용됩니다. mcrypt 패드가 널 (null)로, PKCS # 7 패드가 패딩 길이로, 입력이 정확히 블록 크기 인 경우 추가 블록을 추가합니다. [Mcrypt를 사용하여 PHP에서 AES를 구현 한 교훈] (http://www.leaseweblabs.com/2014/02/aes-php-mcrypt-key-padding/)을 참조하십시오. 참조 : [PKCS # 7 패딩] (http://en.wikipedia.org/wiki/Padding_ (cryptography)) – zaph

+0

조언을 주셔서 대단히 감사드립니다.내가하는 말을 이해한다면 Objective-C *에서 수동으로 제 자신의 덧셈을 추가해야합니다. * 나는 문자열을'CCCrypt'에 보냅니다. 예를 들어, 12 바이트의 일반 텍스트 문자열이있는 경우 문자열 끝에 '04 04 04 04'를 추가하고 그 값을'CCCrypt '에 보내야합니다. 'CCCrypt'는 암호화되기 전에 16 바이트의 패딩을 추가합니다. 그런 다음 PHP에서 문자열을 해독 한 후 마지막 20 바이트를 제거하고 나머지 문자열이 일반 텍스트라고 결론을 내릴 수 있습니다. 그 맞습니까? – Alex