IPhone पर NSString के लिए AES एन्क्रिप्शन


124

क्या कोई मुझे स्ट्रिंग को एन्क्रिप्ट करने में सक्षम होने के लिए सही दिशा में इंगित कर सकता है, एन्क्रिप्टेड डेटा के साथ एक और स्ट्रिंग लौटा सकता है? (मैं AES256 एन्क्रिप्शन के साथ कोशिश कर रहा हूँ।) मैं एक ऐसा तरीका लिखना चाहता हूँ जो दो NSString उदाहरण लेता है, एक को एन्क्रिप्ट करने का संदेश और दूसरा इसे पास करने के लिए 'पासकोड' होने के साथ - मुझे संदेह है कि मुझे उत्पन्न करना होगा पासकोड के साथ एन्क्रिप्शन कुंजी, एक तरह से जिसे उलटा किया जा सकता है यदि पासकोड को एन्क्रिप्टेड डेटा के साथ आपूर्ति की जाती है। विधि को एनक्रिप्टेड डेटा से बनाए गए एनएसएसट्रिंग को वापस करना चाहिए।

मैंने इस पोस्ट पर पहली टिप्पणी में विस्तृत तकनीक की कोशिश की है , लेकिन मुझे अब तक कोई भाग्य नहीं मिला है। Apple का CryptoExercise निश्चित रूप से कुछ है, लेकिन मैं इसका कोई मतलब नहीं निकाल सकता ... मैंने CCCrypt के बहुत सारे संदर्भ देखे हैं , लेकिन मैंने इसे इस्तेमाल करने वाले हर मामले में विफल रहा है।

मुझे एक एन्क्रिप्टेड स्ट्रिंग को डिक्रिप्ट करने में भी सक्षम होना होगा, लेकिन मुझे आशा है कि kCCEncrypt / kCCDecrypt के रूप में सरल है।


1
कृपया ध्यान दें कि मैंने रोब नेपियर के उत्तर के लिए एक इनाम दिया है जिन्होंने उत्तर का सुरक्षित संस्करण प्रदान किया है।
Maarten Bodewes

जवाबों:


126

चूंकि आपने कोई कोड पोस्ट नहीं किया है, इसलिए यह जानना मुश्किल है कि आप किन समस्याओं का सामना कर रहे हैं। हालाँकि, आपके द्वारा लिंक की गई ब्लॉग पोस्ट बहुत ही शालीनता से काम करती प्रतीत होती है ... एक कॉल में अतिरिक्त कॉमा से अलगCCCrypt() जिसमें संकलित त्रुटियां थीं।

उस पोस्ट पर एक बाद की टिप्पणी में यह अनुकूलित कोड शामिल है , जो मेरे लिए काम करता है, और थोड़ा अधिक सरल लगता है। यदि आप NSData श्रेणी के लिए उनके कोड को शामिल करते हैं, तो आप कुछ इस तरह से लिख सकते हैं: (नोट: printf()कॉल केवल विभिन्न बिंदुओं पर डेटा की स्थिति को प्रदर्शित करने के लिए हैं - एक वास्तविक एप्लिकेशन में, इस तरह के मूल्यों को प्रिंट करने का कोई मतलब नहीं होगा ।)

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSString *key = @"my password";
    NSString *secret = @"text to encrypt";

    NSData *plain = [secret dataUsingEncoding:NSUTF8StringEncoding];
    NSData *cipher = [plain AES256EncryptWithKey:key];
    printf("%s\n", [[cipher description] UTF8String]);

    plain = [cipher AES256DecryptWithKey:key];
    printf("%s\n", [[plain description] UTF8String]);
    printf("%s\n", [[[NSString alloc] initWithData:plain encoding:NSUTF8StringEncoding] UTF8String]);

    [pool drain];
    return 0;
}

इस कोड को देखते हुए, और यह तथ्य कि एन्क्रिप्टेड डेटा हमेशा एनएसएसट्रिंग में अच्छी तरह से अनुवाद नहीं करेगा, यह दो तरीकों को लिखने के लिए अधिक सुविधाजनक हो सकता है जो आपके लिए आवश्यक कार्यक्षमता को लपेटते हैं, आगे और पीछे ...

- (NSData*) encryptString:(NSString*)plaintext withKey:(NSString*)key {
    return [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
}

- (NSString*) decryptData:(NSData*)ciphertext withKey:(NSString*)key {
    return [[[NSString alloc] initWithData:[ciphertext AES256DecryptWithKey:key]
                                  encoding:NSUTF8StringEncoding] autorelease];
}

यह निश्चित रूप से स्नो लेपर्ड पर काम करता है, और @Boz रिपोर्ट करता है कि कॉमनट्रिप्टो iPhone पर कोर ओएस का हिस्सा है। 10.4 और 10.5 दोनों के पास है /usr/include/CommonCrypto, हालाँकि 10.5 के लिए मैन पेज है CCCryptor.3ccऔर 10.4 नहीं है, इसलिए YMMV है।


संपादित: देखें इस अनुवर्ती प्रश्न एन्क्रिप्टेड डाटा का प्रतिनिधित्व करने के लिए Base64 एन्कोडिंग का उपयोग पर एक स्ट्रिंग के रूप बाइट्स (आवश्यक होने पर) सुरक्षित, दोषरहित रूपांतरण के उपयोग।


1
धन्यवाद। कॉमनट्रिप्टो iPhone पर कोर ओएस का हिस्सा है, और मैं 10.6 भी चला रहा हूं।
बोज

1
मैंने -1 किया, क्योंकि संदर्भित कोड खतरनाक रूप से असुरक्षित है। इसके बजाय रोब नेपियर के उत्तर को देखें। उनका ब्लॉग प्रविष्टि " robnapier.net/aes-commoncrypto विवरण वास्तव में यह असुरक्षित क्यों है।
एरिक इंगहेम

1
यह समाधान मेरे मामले में काम नहीं करता है। मेरे पास एक स्ट्रिंग है जिसे मैं डिकोड करना चाहता हूं: U2FsdGVkX1 + MEhsbofUNj58m + 8tu9ifAKRiY / Zf8YIw = और मेरे पास चाबी है: 3841808485cd155d932a2d601b8cee2ec। मैं आपके समाधान के साथ कुंजी का उपयोग करके स्ट्रिंग को डिक्रिप्ट नहीं कर सकता। धन्यवाद
जॉर्ज

यह समाधान XCode7 के साथ El Capitan पर एक कोको ऐप में काम नहीं करता है। एआरसी निषिद्ध है autorelease
Volomike

@QuinnTaylor मैं इस उत्तर को संपादित कर सकता हूं, लेकिन जैसा कि आप फिट देखते हैं, आपको इसे बदलने का अवसर देना चाहते हैं। मैंने यहाँ आपके कोड की मरम्मत की । इसके अलावा, आप उस अनुकूलित कोड के बिना इंगित करना चाह सकते हैं , यह संकलन नहीं करेगा। इसलिए, मुझे XCode7 के साथ एल कैपिटन पर एक कोको आवेदन पर काम करने के लिए मिला। अब मैं जो करने की कोशिश कर रहा हूं वह यह पता लगाता है कि इस डेटा को Base64Encode / Base64 कैसे कॉन्फ़िगर किया जाए, ताकि यह कच्चे डेटा को वापस करने के बजाय पारगमन में परेशान किए बिना पारगम्य हो।
Volomike

46

मैंने NSData और NSString के लिए श्रेणियों का एक संग्रह रखा है, जो जेफ लामार्च के ब्लॉग और कुछ संकेतों पर पाए गए समाधानों का उपयोग करता है स्टैक ओवरफ्लो पर यहां क्विन टेलर द्वारा गए हैं।

यह AES256 एन्क्रिप्शन प्रदान करने के लिए NSData का विस्तार करने के लिए श्रेणियों का उपयोग करता है और स्ट्रिंग के लिए सुरक्षित रूप से एन्क्रिप्टेड डेटा को BASE64-एनकोड करने के लिए NSString का विस्तार भी प्रदान करता है।

स्ट्रिंग को एन्क्रिप्ट करने के लिए उपयोग दिखाने के लिए यहां एक उदाहरण दिया गया है:

NSString *plainString = @"This string will be encrypted";
NSString *key = @"YourEncryptionKey"; // should be provided by a user

NSLog( @"Original String: %@", plainString );

NSString *encryptedString = [plainString AES256EncryptWithKey:key];
NSLog( @"Encrypted String: %@", encryptedString );

NSLog( @"Decrypted String: %@", [encryptedString AES256DecryptWithKey:key] );

पूर्ण स्रोत कोड यहाँ प्राप्त करें:

https://gist.github.com/838614

सभी उपयोगी संकेत के लिए धन्यवाद!

- माइकल


NSString * कुंजी = @ "YourEnc एन्क्रिप्शनKey"; // एक उपयोगकर्ता द्वारा प्रदान किया जाना चाहिए क्या हम उपयोगकर्ता द्वारा प्रदान किए गए एक के बजाय एक यादृच्छिक सुरक्षित 256-बिट कुंजी उत्पन्न कर सकते हैं।
प्रणव जायसवाल

Jeff
LaMarche

35

@owlstead, दिए गए किसी एक उत्तर के क्रिप्टोग्राफिक रूप से सुरक्षित संस्करण के लिए आपके अनुरोध के बारे में, कृपया देखें Rryptcor । यह बिल्कुल वही करने के लिए डिज़ाइन किया गया था जिसे आप अनुरोध कर रहे हैं (और यहां सूचीबद्ध कोड के साथ समस्याओं के जवाब में बनाया गया था)।

RNCryptor नमक के साथ PBKDF2 का उपयोग करता है, एक यादृच्छिक IV प्रदान करता है, और HMAC (अपने स्वयं के नमक के साथ PBKDF2 से उत्पन्न) को जोड़ता है। यह तुल्यकालिक और अतुल्यकालिक ऑपरेशन का समर्थन करता है।


दिलचस्प कोड, और शायद अंक के लायक। PBKDF2 के लिए पुनरावृत्ति गणना क्या है और आप HMAC की गणना क्या करते हैं? मैं सिर्फ एन्क्रिप्टेड डेटा मानता हूं? मैं प्रदान किए गए दस्तावेज़ में आसानी से नहीं मिला।
मार्टन बोदवेस

विवरण के लिए "सर्वोत्तम अभ्यास सुरक्षा" देखें। मैं iOS पर 10k पुनरावृत्तियों (एक iPhone 4 पर ~ 80ms) की सिफारिश करता हूं। और हाँ, एन्क्रिप्ट-से-एचएमएसी। मैं शायद "डेटा प्रारूप" पृष्ठ पर आज रात देखूंगा, यह सुनिश्चित करने के लिए कि यह v2.0 पर अद्यतित है (मुख्य डॉक्स अद्यतित हैं, लेकिन मुझे याद नहीं है कि मैंने डेटा प्रारूप पृष्ठ को संशोधित किया है)।
रोब नेपियर

आह, हाँ, डॉक्स में राउंड की संख्या को पाया और कोड को देखा। मैं सफाई कार्यों को देखता हूं और वहां एचएमएसी और एन्क्रिप्शन कुंजी को अलग करता हूं। अगर समय अनुमति देता है तो मैं कोशिश करूंगा और कल एक गहन रूप लूंगा। फिर मैं अंक निर्दिष्ट करूँगा।
मार्टन Bodewes

5
NSData को एन्क्रिप्ट करें, और इसे एक स्ट्रिंग में बदलने के लिए कई Base64 एन्कोडर्स में से एक का उपयोग करें। डेटा-टू-स्ट्रिंग एनकोडर के बिना स्ट्रिंग से स्ट्रिंग तक एन्क्रिप्ट करने का कोई तरीका नहीं है।
रोब नेपियर

1
@ मेरे वकील की सलाह पर (जिन्होंने बेहद रंगीन शब्दों में निर्यात अनुपालन कानून में मेरी कमी का वर्णन किया है ...), मैं अब निर्यात अनुपालन कानून के बारे में सलाह नहीं देता। आपको अपने वकील से चर्चा करनी होगी।
रोब नेपियर

12

मैंने उसके जवाब को अपडेट करने के लिए @QuinnTaylor पर थोड़ा इंतजार किया, लेकिन जब से वह नहीं आया, यहाँ का जवाब थोड़ा और स्पष्ट है और एक तरह से यह XCode7 (और शायद अधिक) पर लोड होगा। मैंने इसे कोको एप्लिकेशन में उपयोग किया है, लेकिन यह संभव है कि एक iOS एप्लिकेशन के साथ भी ठीक काम करेगा। एआरसी की कोई त्रुटि नहीं है।

अपने AppDelegate.m या AppDelegate.mm फ़ाइल में किसी भी @ कार्यान्वयन अनुभाग से पहले चिपकाएँ।

#import <CommonCrypto/CommonCryptor.h>

@implementation NSData (AES256)

- (NSData *)AES256EncryptWithKey:(NSString *)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256+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];

    NSUInteger dataLength = [self length];

    //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(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                     keyPtr, kCCKeySizeAES256,
                                     NULL /* initialization vector (optional) */,
                                     [self bytes], dataLength, /* input */
                                     buffer, bufferSize, /* output */
                                     &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}

- (NSData *)AES256DecryptWithKey:(NSString *)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256+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];

    NSUInteger dataLength = [self length];

    //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(bufferSize);

    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                     keyPtr, kCCKeySizeAES256,
                                     NULL /* initialization vector (optional) */,
                                     [self bytes], dataLength, /* input */
                                     buffer, bufferSize, /* output */
                                     &numBytesDecrypted);

    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}

@end

इन दोनों कार्यों को आप जिस वर्ग की इच्छा रखते हैं उस पर चिपकाएँ। मेरे मामले में, मैंने अपने AppDelegate.mm या AppDelegate.m फ़ाइल में @ परिशिष्ट AppDelegate चुना।

- (NSString *) encryptString:(NSString*)plaintext withKey:(NSString*)key {
    NSData *data = [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
    return [data base64EncodedStringWithOptions:kNilOptions];
}

- (NSString *) decryptString:(NSString *)ciphertext withKey:(NSString*)key {
    NSData *data = [[NSData alloc] initWithBase64EncodedString:ciphertext options:kNilOptions];
    return [[NSString alloc] initWithData:[data AES256DecryptWithKey:key] encoding:NSUTF8StringEncoding];
}

नोट: 1. डिक्रिप्ट करने पर आउटपुट साइज इनपुट साइज से कम होगा जब पेडिंग (PKCS # 7) होगा। बफरसिज़ बढ़ाने का कोई कारण नहीं है, बस एन्क्रिप्टेड डेटा आकार का उपयोग करें। 2. इसके बजाय एक बफर के मॉलोकिंग और फिर dataWithBytesNoCopyबस के NSMutableDataसाथ आवंटित करें dataWithLengthऔर mutableBytesबाइट पॉइंटर के लिए संपत्ति का उपयोग करें और फिर इसे lengthसंपत्ति सेट करके आकार बदलें । 3. एक एन्क्रिप्शन के लिए सीधे स्ट्रिंग का उपयोग करना बहुत असुरक्षित है, एक व्युत्पन्न कुंजी का उपयोग किया जाना चाहिए जैसे कि PBKDF2 द्वारा बनाई गई।
जैफ

@ ज़ैफ़, क्या आप कहीं पास्टबिन / पेस्टी कर सकते हैं ताकि मैं बदलाव देख सकूं? BTW, ऊपर दिए गए कोड पर, मैंने इसे काम करने के लिए क्विन टेलर से देखे गए कोड को केवल अनुकूलित किया। मैं अभी भी इस व्यवसाय को सीख रहा हूं क्योंकि मैं जाता हूं, और आपका इनपुट मेरे लिए बहुत उपयोगी होगा।
Volomike

इस SO उत्तर को देखें और इसमें न्यूनतम त्रुटि हैंडलिंग और एन्क्रिप्शन और डिक्रिप्शन दोनों हैं। डिक्रिप्शन पर बफर को सीमित करने की कोई आवश्यकता नहीं है, यह कम कोड है जो अतिरिक्त के साथ विशेषज्ञता नहीं है अगर प्राप्त करने के लिए बहुत कम है। नल के साथ कुंजी का विस्तार करने के मामले में वांछित है (जो कि नहीं किया जाना चाहिए) बस कुंजी का एक परिवर्तनशील संस्करण बनाएं और लंबाई निर्धारित करें keyData.length = kCCKeySizeAES256;:।
ज़ाफ़

किसी स्ट्रिंग से कुंजी बनाने के लिए PBKDF2 का उपयोग करने के लिए यह SO उत्तर देखें ।
ज़फ़

@ वोलोमाइक यदि मैं इसका उपयोग करता हूं, तो क्या मुझे आईट्यून्स-कनेक्ट पर निर्यात अनुपालन सूचना ( वाईईएस ) का चयन करना चाहिए ?
जैक

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.