2012-12-08 70 views
5

Tôi đang cố triển khai hệ thống trong đó A tạo cặp khóa RSA và gửi khóa công khai tới B. B rồi tạo khóa AES và mã hóa khóa đó bằng khóa công khai, gửi kết quả trở lại đến A. A sau đó giải mã khóa AES bằng khóa riêng RSA của nó, mã hóa dữ liệu bằng khóa AES và gửi nó đến B, sau đó có thể giải mã nó bằng khóa AES.Giải mã RSA trên Android - iPhone

Tôi đã có tất cả điều này làm việc ở phía Android, nhưng tôi không thể nhận được các bên iPhone để chơi bóng (Tôi mới đến Objective C vì vậy đó là lý do tại sao có thể!)

Ban đầu, tôi đã nhận được một lỗi 9809 khi giải mã khóa AES bằng khóa riêng RSA, điều này không được dịch một cách vô tình thành lỗi chung. Nghiên cứu các điểm lỗi cho padding (tôi đang sử dụng PKCS1 Padding) là vấn đề, chuyển sang No Padding cho phép khách hàng iPhone giải mã thành công, nhưng khóa AES được giải mã khác với khóa được tạo trên máy khách Android.

Mục tiêu C rất mới đối với tôi và tôi chắc chắn rằng tôi chỉ đang mắc lỗi học sinh, bất cứ ai có thể chỉ cho tôi đúng hướng không?

iPhone RSA thế hệ cặp khóa

static const unsigned char _encodedRSAEncryptionOID[15] = { 

    /* Sequence of length 0xd made up of OID followed by NULL */ 
    0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 
    0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00 

}; 

NSData * publicTag = [publicKeyIdentifier dataUsingEncoding:NSUTF8StringEncoding]; 

// Now lets extract the public key - build query to get bits 
NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init]; 

[queryPublicKey setObject:(__bridge id) kSecClassKey 
        forKey:(__bridge id) kSecClass]; 
[queryPublicKey setObject:publicTag 
        forKey:(__bridge id) kSecAttrApplicationTag]; 
[queryPublicKey setObject:(__bridge id) kSecAttrKeyTypeRSA 
        forKey:(__bridge id) kSecAttrKeyType]; 
[queryPublicKey setObject:[NSNumber numberWithBool:YES] 
        forKey:(__bridge id) kSecReturnData]; 

CFTypeRef pk; 
OSStatus err = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, &pk); 

NSData* publicKeyBits = (__bridge_transfer NSData*)pk; 

if (err != noErr) { 
    return nil; 
} 

// OK - that gives us the "BITSTRING component of a full DER 
// encoded RSA public key - we now need to build the rest 

unsigned char builder[15]; 
NSMutableData * encKey = [[NSMutableData alloc] init]; 
int bitstringEncLength; 

// When we get to the bitstring - how will we encode it? 
if ([publicKeyBits length ] + 1 < 128) 
    bitstringEncLength = 1 ; 
else 
    bitstringEncLength = (([publicKeyBits length ] +1)/256) + 2 ; 

// Overall we have a sequence of a certain length 
builder[0] = 0x30; // ASN.1 encoding representing a SEQUENCE 
// Build up overall size made up of - 
// size of OID + size of bitstring encoding + size of actual key 
size_t i = sizeof(_encodedRSAEncryptionOID) + 2 + bitstringEncLength + 
[publicKeyBits length]; 
size_t j = encodeLength(&builder[1], i); 
[encKey appendBytes:builder length:j +1]; 

// First part of the sequence is the OID 
[encKey appendBytes:_encodedRSAEncryptionOID 
      length:sizeof(_encodedRSAEncryptionOID)]; 

// Now add the bitstring 
builder[0] = 0x03; 
j = encodeLength(&builder[1], [publicKeyBits length] + 1); 
builder[j+1] = 0x00; 
[encKey appendBytes:builder length:j + 2]; 

// Now the actual key 
[encKey appendData:publicKeyBits]; 

// Now translate the result to a Base64 string 
Base64* base64 = [[Base64 alloc] init]; 
NSString* ret = [base64 encode:encKey]; 

return ret; 

Tái tạo khóa công khai, tạo ra chìa khóa AES và mã hóa nó trên Android (chú ý getBytes(...)getString(...) chỉ làm một số encoding.decoding base64)

KeyGenerator keyGen = KeyGenerator.getInstance("AES"); 
keyGen.init(256, new SecureRandom()); 
SecretKey secretKey = keyGen.generateKey(); 

byte[] publicKeyBytes = getBytes(publicKey.getKey()); 
PublicKey rsaKey = KeyFactory.getInstance("RSA") 
    .generatePublic(new X509EncodedKeySpec(publicKeyBytes)); 

Cipher cipher = Cipher.getInstance(RSA); 
cipher.init(Cipher.ENCRYPT_MODE, rsaKey); 

String keyEncoded = getString(key); 

return getString(encryptedKeyBytes)); 

Giải mã khóa AES trên iPhone

Base64* base64 = [[Base64 alloc] init]; 
NSData* cipherText = [base64 decode:textBase64]; 

const uint8_t *cipherBuffer = (const uint8_t*)[cipherText bytes]; 

size_t cipherBufferSize = strlen((char *) cipherBuffer); 

uint8_t *plainBuffer = (uint8_t *)calloc(SecKeyGetBlockSize(publicKey), sizeof(uint8_t)); 
size_t plainBufferSize = SecKeyGetBlockSize(publicKey); 

OSStatus status = SecKeyDecrypt(privateKey, 
         kSecPaddingPKCS1, 
         &cipherBuffer[0], 
         cipherBufferSize, 
         &plainBuffer[0], 
         &plainBufferSize 
         ); 

NSData* finalData = [[NSData alloc] initWithBytes:plainBuffer length:plainBufferSize]; 
NSString *result = [base64 encode:finalData]; 

return result; 

EDIT: Tôi nghĩ rằng tôi đã thu hẹp này xuống một chút, đoạn mã sau từ Giải mã những phần quan trọng AES mã của tôi:

NSData* cipherText = [base64 decode:text]; 
NSLog(@"cipherText %@", cipherText); 
const uint8_t *cipherBuffer = (const uint8_t*)[cipherText bytes]; 
NSLog(@"cipherBuffer %s", cipherBuffer); 

size_t cipherBufferSize = strlen((char *) cipherBuffer); 
NSLog(@"cipherBufferSize %zd", cipherBufferSize); 

Tạo đầu ra sau trong giao diện điều khiển:

cipherText <31226275 cc56069a e96b7f6f 0fbee853 32d07de6 436755c9 e27b88a6 04176947  d57f7108 de68e5b8 49595e9f 09bceb30 1d615927 c205f205 eb644fa7 bff6c02b 885605de eb5bd4ee 473bb4d3 df768017 24552706 ea67f347 2952614e ad63f3c6 eb0022d3 a0513afa 0e59ba63 cb5c9787 a40ecad4 a866fdc7 26b60cc2 088a3499 a84c0595 fb1c2be8 5c85b88d 7856b4bd 655f6fec 905ca221 d6bb03c0 7329410b b235ef8f 1ef97a64 7fabb280 90118ff7 4b1e91f6 162134fc 5cbf962e 813e39e7 993b0fb9 e3c4b30c ef6a7b90 9d64c41a 1211ab34 c2c52235 d2ec3b65 d1314cee 70eafe65 f4a6c5e4 660cf889 4540a784 d14cc5a8 49a12c43 c76f7f03 5fbcd44f> 
cipherBuffer 1"buÃVöÈkoæËS2–}ÊCgU…‚{à¶iG’qfihÂ∏IY^ü ºÎ0aY'¬ÚÎdOßøˆ¿+àVfiÎ[‘ÓG;¥”flvÄ$U'ÍgÛG)RaN≠cÛ∆Î 
cipherBufferSize 97 

Thỉnh thoảng, nó đi kèm với kích thước bộ đệm mã hóa 256 như dự kiến ​​và giải mã hoạt động hoàn hảo! Tôi biết tôi phải thiếu một cái gì đó hiển nhiên?

+0

* B sau đó tạo khóa AES và mã hóa nó bằng khóa công khai, gửi kết quả trở lại A *> Ghi chú bên - bạn đã cân nhắc việc B ký dữ liệu trước khi mã hóa chưa? Làm thế nào để A biết chìa khóa đến từ B? –

+2

Tôi không biết gì về iPhone nhưng tôi hoài nghi về một số phát biểu của bạn. "Tôi đã có tất cả điều này làm việc ở phía Android" có nghĩa là gì? Việc mã hóa đơn giản mà không tạo ra lỗi không có nghĩa là nó đang hoạt động. Bạn cũng có thể giải mã chính xác ở phía bên Android không? Ngoài ra, bằng cách loại bỏ yêu cầu padding trên iPhone, bạn đã loại bỏ cơ chế duy nhất mà iPhone phát hiện ra một vấn đề. Nó không trả về lỗi vì nó không có cách nào phát hiện lỗi.Nó vẫn có thể là bất cứ điều gì và tất cả mọi thứ là không chính xác. Để tùy chọn đệm PKCS1 trên. –

+0

Thực tế là việc loại bỏ đệm tạo ra khóa được giải mã sai cho thấy rằng bạn có tiền trên đây. Tôi thậm chí không biết bắt đầu từ đâu khi làm việc với những điều sai trái! Bởi "tất cả làm việc ở phía Android" Tôi có nghĩa là tôi có thể thực hiện toàn bộ quá trình một cách chính xác giữa hai thiết bị Android. –

Trả lời

0

Vấn đề của bạn với chức năng strlen, không hoạt động trên dữ liệu nhị phân nói chung, nó chỉ hoạt động trên dữ liệu nhị phân đại diện cho văn bản và kết thúc bằng byte có giá trị bằng không (\0). Thay vào đó, bạn nên sử dụng kích thước thực tế của bản mã.

Vì vậy, hiện tại khối mã của bạn sẽ thất bại nếu bản mã có chứa một byte có giá trị bằng không, hoặc nếu nó không được theo sau bởi byte không có giá trị.

Các vấn đề liên quan