2012-11-09 18 views
10

मैं एंड्रॉइड और आईफोन प्लेटफ़ॉर्म दोनों पर एईएस एल्गोरिदम का उपयोग करके कुछ टेक्स्ट एन्क्रिप्ट करने की कोशिश कर रहा हूं। मेरी समस्या यह है कि, एक ही एन्क्रिप्शन/डिक्रिप्शन एल्गोरिदम (एईएस-128) और एक ही निश्चित चर (कुंजी, चतुर्थ, मोड) का उपयोग करके, मुझे दोनों प्लेटफार्मों पर अलग-अलग परिणाम मिलते हैं। मैं दोनों प्लेटफॉर्म से कोड नमूने शामिल कर रहा हूं, जिसका उपयोग मैं एन्क्रिप्शन/डिक्रिप्शन का परीक्षण करने के लिए कर रहा हूं। मैं यह निर्धारित करने में कुछ मदद की सराहना करता हूं कि मैं क्या गलत कर रहा हूं।एंड्रॉइड और आईफोन में एईएस-128 का उपयोग करके एन्क्रिप्शन (विभिन्न परिणाम)

  • कुंजी: "123456789abcdefg"
  • चतुर्थ: "1111111111111111"
  • सादा पाठ: "HelloThere"
  • मोड: "एईएस/सीबीसी/NoPadding"

एंड्रॉयड कोड:

public class Crypto { 
    private final static String HEX = "ABCDEF"; 

    public static String encrypt(String seed, String cleartext) 
      throws Exception { 
     byte[] rawKey = getRawKey(seed.getBytes()); 
     byte[] result = encrypt(rawKey, cleartext.getBytes()); 
     return toHex(result); 
    } 

    public static String decrypt(String seed, String encrypted) 
      throws Exception { 
     byte[] rawKey = getRawKey(seed.getBytes()); 
     byte[] enc = toByte(encrypted); 
     byte[] result = decrypt(rawKey, enc); 
     return new String(result); 
    } 

    private static byte[] getRawKey(byte[] seed) throws Exception { 
     KeyGenerator kgen = KeyGenerator.getInstance("CBC"); 
     SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
     sr.setSeed(seed); 
     kgen.init(128, sr); // 192 and 256 bits may not be available 
     SecretKey skey = kgen.generateKey(); 
     byte[] raw = skey.getEncoded(); 
     return raw; 
    } 

    private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception { 
     SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); 
     Cipher cipher = Cipher.getInstance("AES"); 
     cipher.init(Cipher.ENCRYPT_MODE, skeySpec); 
     byte[] encrypted = cipher.doFinal(clear); 
     return encrypted; 
    } 

    private static byte[] decrypt(byte[] raw, byte[] encrypted) 
      throws Exception { 
     SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); 
     Cipher cipher = Cipher.getInstance("AES"); 
     cipher.init(Cipher.DECRYPT_MODE, skeySpec); 
     byte[] decrypted = cipher.doFinal(encrypted); 
     return decrypted; 
    } 

    public static String toHex(String txt) { 
     return toHex(txt.getBytes()); 
    } 

    public static String fromHex(String hex) { 
     return new String(toByte(hex)); 
    } 

    public static byte[] toByte(String hexString) { 
     int len = hexString.length()/2; 
     byte[] result = new byte[len]; 
     for (int i = 0; i < len; i++) 
      result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 
        16).byteValue(); 
     return result; 
    } 

    public static String toHex(byte[] buf) { 
     if (buf == null) 
      return ""; 

     StringBuffer result = new StringBuffer(2 * buf.length); 
     for (int i = 0; i < buf.length; i++) { 
      appendHex(result, buf[i]); 
     } 

     return result.toString(); 
    } 

    private static void appendHex(StringBuffer sb, byte b) { 
     sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f)); 
    } 
} 

IPhone (ऑब्जेक्टिव-सी) कोड:

- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData { 

    NSData* secretKey = [Cipher md5:cipherKey]; 

    CCCryptorRef cryptor = NULL; 
    CCCryptorStatus status = kCCSuccess; 

    uint8_t iv[kCCBlockSizeAES128]; 
    memset((void *) iv, 0x0, (size_t) sizeof(iv)); 

    status = CCCryptorCreate(encryptOrDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 
         [secretKey bytes], kCCKeySizeAES128, iv, &cryptor); 

    if (status != kCCSuccess) { 
     return nil; 
    } 

    size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[inputData length], true); 

    void * buf = malloc(bufsize * sizeof(uint8_t)); 
    memset(buf, 0x0, bufsize); 

    size_t bufused = 0; 
    size_t bytesTotal = 0; 

    status = CCCryptorUpdate(cryptor, [inputData bytes], (size_t)[inputData length], 
         buf, bufsize, &bufused); 

    if (status != kCCSuccess) { 
     free(buf); 
     CCCryptorRelease(cryptor); 
     return nil; 
    } 

    bytesTotal += bufused; 

    status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused); 

    if (status != kCCSuccess) { 
     free(buf); 
     CCCryptorRelease(cryptor); 
     return nil; 
    } 

    bytesTotal += bufused; 

    CCCryptorRelease(cryptor); 

    return [NSData dataWithBytesNoCopy:buf length:bytesTotal]; 
} 

+ (NSData *) md5:(NSString *) stringToHash { 

    const char *src = [stringToHash UTF8String]; 

    unsigned char result[CC_MD5_DIGEST_LENGTH]; 

    CC_MD5(src, strlen(src), result); 

    return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH]; 
} 

मेरे संदर्भ में से कुछ:

+0

कौन सा 'एन्क्रिप्ट()' विधि आप उपयोग कर रहे हैं? आपका सवाल एक गड़बड़ है। केवल आवश्यक कोड प्रदान करें। – erickson

+0

आप इस समाधान का उपयोग कर सकते हैं, यह मेरे लिए काम: http://stackoverflow.com/questions/17535918/aes-gets-different-results: [1] [1] [लिंक यहाँ विवरण दर्ज] -इन-आईओएस-एंड-जावा? answertab = सक्रिय # टैब-टॉप – salimido

+0

आपको एन्क्रिप्टेड डेटा को बराबर होने की आवश्यकता क्यों है? शायद आप बिना किसी कारण के अपने कोड को कम सुरक्षित बना देंगे। अधिकांश उपयोग मामलों में केवल डिक्रिप्ट डेटा बराबर होना चाहिए। देखें crypto.stackexchange.com/q/5094 –

उत्तर

3

Android पर, आप उपयोग कर रहे हैं getBytes()। यह एक त्रुटि है क्योंकि इसका मतलब है कि आप एक ज्ञात वर्णमाला के बजाय डिफ़ॉल्ट वर्णसेट का उपयोग कर रहे हैं। इसके बजाए getBytes("UTF-8") का उपयोग करें ताकि आप जान सकें कि आप किन बाइट्स प्राप्त करने जा रहे हैं।

मुझे उद्देश्य-सी के बराबर नहीं पता है, लेकिन डिफ़ॉल्ट पर भरोसा नहीं करते हैं। स्ट्रिंग्स को बाइट्स में कनवर्ट करते समय स्पष्ट रूप से यूटीएफ -8 निर्दिष्ट करें। इस तरह आप दोनों तरफ एक ही बाइट प्राप्त करेंगे।

मैं यह भी ध्यान देता हूं कि आप उद्देश्य-सी कोड में MD5 का उपयोग कर रहे हैं लेकिन एंड्रॉइड कोड में नहीं। क्या यह जानबूझकर है?

7

इससे मुझे कोई आश्चर्य नहीं होता कि आपको अलग-अलग परिणाम मिलते हैं।

आपकी समस्या यह है कि आप मुख्य व्युत्पन्न के लिए SHA1PRNG का दुरुपयोग करते हैं। AFAIK कोई सामान्य मानक नहीं है कि SHA1PRNG आंतरिक रूप से कैसे काम करता है। AFAIR भी J2SE और Bouncycaste कार्यान्वयन आउटपुट एक ही बीज का उपयोग कर अलग-अलग परिणाम।

इसलिए आपके getRawKey(byte[] seed) के कार्यान्वयन से आपको यादृच्छिक कुंजी मिल जाएगी। यदि आप एन्क्रिप्शन के लिए कुंजी का उपयोग करते हैं तो आपको परिणाम मिल रहा है जो उस कुंजी पर निर्भर करता है। चूंकि कुंजी यादृच्छिक है, आपको आईओएस पर एक ही कुंजी नहीं मिल जाएगी और इसलिए आपको एक अलग परिणाम मिल रहा है।

यदि आप चाहते हैं कि एक प्रमुख व्युत्पन्न कार्य PBKDF2 जैसे फ़ंक्शन का उपयोग करें, तो मुख्य व्युत्पन्न के संबंध में लगभग पूरी तरह से मानकीकृत है।

+1

+1 - कुंजी नाम में है, psuedo यादृच्छिक संख्या जनरेटर। विभिन्न कार्यान्वयन एक ही परिणाम नहीं देते हैं, भले ही आप एक ही बीज का उपयोग करते हों। – Qwerky

+0

सबसे पहले मैं आपकी प्रतिक्रिया के लिए धन्यवाद देना चाहता हूं लेकिन यदि आप मेरे लिए थोड़ा उलझन में हैं तो –

+0

अपने getRawKey (..) कार्यान्वयन के बारे में मेरा अद्यतन उत्तर देखें, तो मैं आपके प्रयास की सराहना करता हूं। – Robert

2

password-based AES encryption, के लिए मेरा उत्तर देखें, इसलिए आप प्रभावी रूप से अपने "बीज" को पासवर्ड के रूप में उपयोग कर रहे हैं। (यदि आप यही चाहते हैं तो बस 256 से 128 की मुख्य लंबाई बदलें।)

एक ही मूल्य के साथ एक डीआरबीजी बीजिंग करके एक ही कुंजी उत्पन्न करने की कोशिश करना विश्वसनीय नहीं है।

अगला, आप अपने एंड्रॉइड एन्क्रिप्शन में सीबीसी या IV का उपयोग नहीं कर रहे हैं। मेरा उदाहरण दिखाता है कि यह ठीक से कैसे करें। वैसे, आपको अपने द्वारा एन्क्रिप्ट किए गए प्रत्येक संदेश के लिए एक नया IV उत्पन्न करने की आवश्यकता है, जैसा कि मेरा उदाहरण दिखाता है, और इसे सिफर टेक्स्ट के साथ भेजता है। अन्यथा, सीबीसी का उपयोग करने में कोई बात नहीं है।

0

यदि आप एंड्रॉइड और आईफोन के लिए संगत कोड का उदाहरण चाहते हैं, तो आईओएस के लिए RNCryptor library और जावा/एंड्रॉइड के लिए JNCryptor library देखें।

दोनों परियोजनाएं ओपन सोर्स हैं और एक सामान्य डेटा प्रारूप साझा करती हैं। इन पुस्तकालयों में, एईएस 256-बिट का उपयोग किया जाता है, हालांकि 128-बिट एईएस का समर्थन करने के लिए आवश्यक होने पर कोड को अनुकूलित करना मुश्किल होगा।

स्वीकार्य उत्तर के अनुसार, दोनों पुस्तकालय पीबीकेडीएफ 2 का उपयोग करते हैं।

14

iPhone के लिए मैं AESCrypt-ObjC इस्तेमाल किया, और Android के लिए इस कोड का उपयोग:

public class AESCrypt { 

    private final Cipher cipher; 
    private final SecretKeySpec key; 
    private AlgorithmParameterSpec spec; 


    public AESCrypt(String password) throws Exception 
    { 
    // hash password with SHA-256 and crop the output to 128-bit for key 
    MessageDigest digest = MessageDigest.getInstance("SHA-256"); 
    digest.update(password.getBytes("UTF-8")); 
    byte[] keyBytes = new byte[32]; 
    System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length); 

    cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); 
    key = new SecretKeySpec(keyBytes, "AES"); 
    spec = getIV(); 
    }  

    public AlgorithmParameterSpec getIV() 
    { 
    byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; 
    IvParameterSpec ivParameterSpec; 
    ivParameterSpec = new IvParameterSpec(iv); 

    return ivParameterSpec; 
    } 

    public String encrypt(String plainText) throws Exception 
    { 
    cipher.init(Cipher.ENCRYPT_MODE, key, spec); 
    byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8")); 
    String encryptedText = new String(Base64.encode(encrypted, Base64.DEFAULT), "UTF-8"); 

    return encryptedText; 
    } 

    public String decrypt(String cryptedText) throws Exception 
    { 
    cipher.init(Cipher.DECRYPT_MODE, key, spec); 
    byte[] bytes = Base64.decode(cryptedText, Base64.DEFAULT); 
    byte[] decrypted = cipher.doFinal(bytes); 
    String decryptedText = new String(decrypted, "UTF-8"); 

    return decryptedText; 
    } 
} 
+3

-1 एक निश्चित चतुर्थ का उपयोग न करें। http://crypto.stackexchange.com/q/5094 –

+1

@Chris यह एईएसक्रिप्ट-ओबीजेसी आईओएस लाइब्रेरी के साथ एंड्रॉइड कोड को संरेखित करने के लिए किया गया था। एईएसक्रिप्ट-ओबीजेसी जोड़ें मेरे द्वारा रखरखाव नहीं कर रहा है। – Dimentar