एंड्रॉइड में एईएस एन्क्रिप्शन का उपयोग करने के लिए सर्वोत्तम अभ्यास क्या हैं?


90

मैं यह सवाल क्यों पूछता हूं:

मुझे पता है कि एईएस एन्क्रिप्शन के बारे में बहुत सारे सवाल हैं, यहां तक ​​कि एंड्रॉइड के लिए भी। और अगर आप वेब सर्च करते हैं तो बहुत सारे कोड स्निपेट हैं। लेकिन हर एक पेज पर, हर स्टैक ओवरफ्लो प्रश्न में, मुझे बड़े अंतर के साथ एक और कार्यान्वयन मिलता है।

इसलिए मैंने "सर्वश्रेष्ठ अभ्यास" खोजने के लिए यह प्रश्न बनाया। मुझे उम्मीद है कि हम सबसे महत्वपूर्ण आवश्यकताओं की एक सूची एकत्र कर सकते हैं और एक कार्यान्वयन स्थापित कर सकते हैं जो वास्तव में सुरक्षित है!

मैं आरंभीकरण वैक्टर और लवण के बारे में पढ़ता हूं। सभी कार्यान्वयन मुझे नहीं मिले, जिनमें ये विशेषताएं थीं। तो क्या आपको इसकी आवश्यकता है? क्या यह सुरक्षा को बहुत बढ़ाता है? आप इसे कैसे लागू करते हैं? यदि एन्क्रिप्ट किया गया डेटा डिक्रिप्ट नहीं किया जा सकता है तो एल्गोरिथ्म को अपवादों को उठाना चाहिए? या कि असुरक्षित है और यह सिर्फ एक अपठनीय स्ट्रिंग लौटना चाहिए? क्या एल्गोरिथ्म SHA के बजाय Bcrypt का उपयोग कर सकता है?

इन दो कार्यान्वयनों के बारे में मुझे क्या मिला? क्या वे ठीक हैं? बिल्कुल सही या कुछ महत्वपूर्ण बातें याद आ रही हैं? इनमें से क्या सुरक्षित है?

एल्गोरिथ्म को एन्क्रिप्शन के लिए एक स्ट्रिंग और एक "पासवर्ड" लेना चाहिए और फिर उस पासवर्ड के साथ स्ट्रिंग को एन्क्रिप्ट करना चाहिए। आउटपुट फिर से एक स्ट्रिंग (हेक्स या बेस 64?) होना चाहिए। निश्चित रूप से डिक्रिप्शन भी संभव होना चाहिए।

Android के लिए सही AES कार्यान्वयन क्या है?

कार्यान्वयन # 1:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class AdvancedCrypto implements ICrypto {

        public static final String PROVIDER = "BC";
        public static final int SALT_LENGTH = 20;
        public static final int IV_LENGTH = 16;
        public static final int PBE_ITERATION_COUNT = 100;

        private static final String RANDOM_ALGORITHM = "SHA1PRNG";
        private static final String HASH_ALGORITHM = "SHA-512";
        private static final String PBE_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";
        private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
        private static final String SECRET_KEY_ALGORITHM = "AES";

        public String encrypt(SecretKey secret, String cleartext) throws CryptoException {
                try {

                        byte[] iv = generateIv();
                        String ivHex = HexEncoder.toHex(iv);
                        IvParameterSpec ivspec = new IvParameterSpec(iv);

                        Cipher encryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
                        encryptionCipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);
                        byte[] encryptedText = encryptionCipher.doFinal(cleartext.getBytes("UTF-8"));
                        String encryptedHex = HexEncoder.toHex(encryptedText);

                        return ivHex + encryptedHex;

                } catch (Exception e) {
                        throw new CryptoException("Unable to encrypt", e);
                }
        }

        public String decrypt(SecretKey secret, String encrypted) throws CryptoException {
                try {
                        Cipher decryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
                        String ivHex = encrypted.substring(0, IV_LENGTH * 2);
                        String encryptedHex = encrypted.substring(IV_LENGTH * 2);
                        IvParameterSpec ivspec = new IvParameterSpec(HexEncoder.toByte(ivHex));
                        decryptionCipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
                        byte[] decryptedText = decryptionCipher.doFinal(HexEncoder.toByte(encryptedHex));
                        String decrypted = new String(decryptedText, "UTF-8");
                        return decrypted;
                } catch (Exception e) {
                        throw new CryptoException("Unable to decrypt", e);
                }
        }

        public SecretKey getSecretKey(String password, String salt) throws CryptoException {
                try {
                        PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), HexEncoder.toByte(salt), PBE_ITERATION_COUNT, 256);
                        SecretKeyFactory factory = SecretKeyFactory.getInstance(PBE_ALGORITHM, PROVIDER);
                        SecretKey tmp = factory.generateSecret(pbeKeySpec);
                        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), SECRET_KEY_ALGORITHM);
                        return secret;
                } catch (Exception e) {
                        throw new CryptoException("Unable to get secret key", e);
                }
        }

        public String getHash(String password, String salt) throws CryptoException {
                try {
                        String input = password + salt;
                        MessageDigest md = MessageDigest.getInstance(HASH_ALGORITHM, PROVIDER);
                        byte[] out = md.digest(input.getBytes("UTF-8"));
                        return HexEncoder.toHex(out);
                } catch (Exception e) {
                        throw new CryptoException("Unable to get hash", e);
                }
        }

        public String generateSalt() throws CryptoException {
                try {
                        SecureRandom random = SecureRandom.getInstance(RANDOM_ALGORITHM);
                        byte[] salt = new byte[SALT_LENGTH];
                        random.nextBytes(salt);
                        String saltHex = HexEncoder.toHex(salt);
                        return saltHex;
                } catch (Exception e) {
                        throw new CryptoException("Unable to generate salt", e);
                }
        }

        private byte[] generateIv() throws NoSuchAlgorithmException, NoSuchProviderException {
                SecureRandom random = SecureRandom.getInstance(RANDOM_ALGORITHM);
                byte[] iv = new byte[IV_LENGTH];
                random.nextBytes(iv);
                return iv;
        }

}

स्रोत: http://pocket-for-android.1047292.n5.nabble.com/Enc एन्क्रिप्शन-method- and- reading-the-Dropbox-backup-td4344194.html

कार्यान्वयन # 2:

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * Usage:
 * <pre>
 * String crypto = SimpleCrypto.encrypt(masterpassword, cleartext)
 * ...
 * String cleartext = SimpleCrypto.decrypt(masterpassword, crypto)
 * </pre>
 * @author ferenc.hechler
 */
public class SimpleCrypto {

    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("AES");
        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 final static String HEX = "0123456789ABCDEF";
    private static void appendHex(StringBuffer sb, byte b) {
        sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
    }

}

स्रोत: http://www.tutorials-android.com/learn/How_to_encrypt_and_decrypt_str..html


मैं समाधान 1 को लागू करने की कोशिश कर रहा हूं, लेकिन इसके लिए कुछ वर्गों की जरूरत है। क्या आपके पास पूर्ण स्रोत कोड है?
एल्बंक्स

1
नहीं, मुझे खेद नहीं है। लेकिन मैं यह बस को हटा कर काम कर मिल गया implements ICryptoऔर बदलते throws CryptoExceptionकरने के लिए throws Exceptionऔर इतने पर। इसलिए आपको उन कक्षाओं की आवश्यकता नहीं होगी।
caw

लेकिन यह भी HexEncoder वर्ग गायब है? मुझे यह कहां मिल सकता है?
अल्बानक्स

HexEncoder BouncyCastle लाइब्रेरी का हिस्सा है, मुझे लगता है। आप बस इसे डाउनलोड कर सकते हैं। या आप "बाइट [] से हेक्स" और दूसरे तरीके से जावा के लिए गूगल कर सकते हैं।
caw

धन्यवाद मार्को। लेकिन मैं वहाँ 3 तरीके हैं कि नोटिस getSecretKey, getHash, generateSaltपहले कार्यान्वयन कि अप्रयुक्त हैं। हो सकता है कि मैं गलत हूं, लेकिन व्यवहार में स्ट्रिंग को एन्क्रिप्ट करने के लिए इस वर्ग का उपयोग कैसे किया जा सकता है?
अल्बानक्स

जवाबों:


37

न तो आप अपने प्रश्न में जो क्रियान्वयन देते हैं, वह पूरी तरह सही है, और न ही आपके द्वारा दिया गया कार्यान्वयन वैसा ही होना चाहिए जैसा है। किस प्रकार, मैं एंड्रॉइड में पासवर्ड-आधारित एन्क्रिप्शन के पहलुओं पर चर्चा करूंगा।

कीज़ और हैश

मैं नमक के साथ पासवर्ड आधारित प्रणाली पर चर्चा करना शुरू करूंगा। नमक एक बेतरतीब ढंग से उत्पन्न संख्या है। यह "कटौती" नहीं है। कार्यान्वयन 1 में एक generateSalt()विधि शामिल है जो क्रिप्टोग्राफिक रूप से मजबूत यादृच्छिक संख्या उत्पन्न करती है। क्योंकि नमक सुरक्षा के लिए महत्वपूर्ण है, इसे उत्पन्न होने के बाद इसे गुप्त रखा जाना चाहिए, हालांकि इसे केवल एक बार उत्पन्न करने की आवश्यकता होती है। यदि यह एक वेब साइट है, तो नमक को गुप्त रखना अपेक्षाकृत आसान है, लेकिन स्थापित अनुप्रयोगों (डेस्कटॉप और मोबाइल उपकरणों के लिए) के लिए, यह बहुत अधिक कठिन होगा।

विधि getHash()दिए गए पासवर्ड और नमक का एक हैश, एक स्ट्रिंग में समाप्‍त होती है। उपयोग किया गया एल्गोरिथ्म SHA-512 है, जो 512-बिट हैश लौटाता है। यह विधि एक हैश है कि एक स्ट्रिंग की अखंडता की जाँच के लिए उपयोगी है, तो यह getHash()सिर्फ एक पासवर्ड या सिर्फ एक नमक के साथ कॉल करके इस्तेमाल किया जा सकता है , क्योंकि यह बस दोनों मापदंडों को समाप्‍त करता है। चूंकि यह पद्धति पासवर्ड-आधारित एन्क्रिप्शन सिस्टम में उपयोग नहीं की जाएगी, इसलिए मैं आगे इसकी चर्चा नहीं करूंगा।

विधि getSecretKey(), charपासवर्ड की एक सरणी से एक कुंजी और एक हेक्स-एन्कोडेड नमक प्राप्त करता है, जैसा कि से लौटा है generateSalt()। उपयोग किया गया एल्गोरिथ्म PBKDF1 है (मुझे लगता है) PKCS5 से SHA-256 हैश फ़ंक्शन के रूप में है, और एक 256-बिट कुंजी देता है। getSecretKey()बार-बार पासवर्ड, हैश, और एक काउंटर बनाकर एक कुंजी उत्पन्न करता है, ( PBE_ITERATION_COUNT100 में , यहाँ दी गई पुनरावृत्ति गिनती तक ), एक ब्रूट-बल हमले को माउंट करने के लिए आवश्यक समय को बढ़ाने के लिए। नमक की लंबाई कम से कम तब तक होनी चाहिए जब तक कुंजी उत्पन्न हो, इस मामले में, कम से कम 256 बिट्स। अनुचित गणना में देरी किए बिना पुनरावृति गणना को यथासंभव लंबे समय तक सेट किया जाना चाहिए। कुंजी व्युत्पत्ति में लवण और पुनरावृत्ति के बारे में अधिक जानकारी के लिए, RFC2898 में अनुभाग 4 देखें ।

हालांकि, जावा के PBE में कार्यान्वयन त्रुटिपूर्ण है यदि पासवर्ड में यूनिकोड वर्ण होते हैं, अर्थात, जिनका प्रतिनिधित्व करने के लिए 8 से अधिक बिट्स की आवश्यकता होती है। जैसा कि कहा गया है PBEKeySpec, "पीकेसीएस # 5 में परिभाषित पीबीई तंत्र प्रत्येक वर्ण के केवल कम क्रम 8 बिट्स को देखता है"। इस समस्या के इर्द-गिर्द काम करने के लिए, आप इसे पास करने से पहले पासवर्ड में सभी 16-बिट वर्णों की एक हेक्स स्ट्रिंग (जिसमें केवल 8-बिट वर्ण होंगे) उत्पन्न करने का प्रयास कर सकते हैं PBEKeySpec। उदाहरण के लिए, "एबीसी" "004100420043" बन जाता है। यह भी ध्यान दें कि PBEKeySpec "पासवर्ड को एक चार सरणी के रूप में अनुरोध करता है, इसलिए इसे [ clearPassword()जब किया गया हो] ओवरराइट किया जा सकता है"। ("स्मृति में तार की रक्षा" के संबंध में, इस प्रश्न को देखें ।) मुझे कोई समस्या नहीं दिख रही है, हालांकि,

एन्क्रिप्शन

एक बार एक कुंजी उत्पन्न होने के बाद, हम इसका उपयोग पाठ को एन्क्रिप्ट और डिक्रिप्ट करने के लिए कर सकते हैं।

कार्यान्वयन 1 में, सिफर एल्गोरिथ्म का उपयोग किया जाता है AES/CBC/PKCS5Padding, अर्थात, सिफर ब्लॉक चाइनिंग (CBC) सिफर मोड में AES, PKCS # 5 में परिभाषित पैडिंग के साथ। (अन्य एईएस सिफर मोड में काउंटर मोड (सीटीआर), इलेक्ट्रॉनिक कोडबुक मोड (ईसीबी), और गैलोज काउंटर मोड (जीसीएम) शामिल हैं। स्टैक ओवरफ्लो पर एक अन्य प्रश्न के उत्तर हैं जिनमें विभिन्न एईएस सिफर मोड और उपयोग करने के लिए अनुशंसित लोगों के बारे में विस्तार से चर्चा की गई है। ज्ञात हो, भी, कि CBC मोड एन्क्रिप्शन पर कई हमले हैं, जिनमें से कुछ का उल्लेख RFC 7457 में किया गया है।)

ध्यान दें कि आपको एक एन्क्रिप्शन मोड का उपयोग करना चाहिए जो अखंडता के लिए एन्क्रिप्टेड डेटा की भी जांच करता है (उदाहरण के लिए, संबंधित डेटा के साथ प्रमाणित एन्क्रिप्शन , एईएडी, आरएफसी 5116 में वर्णित)। हालाँकि, AES/CBC/PKCS5Paddingअखंडता जाँच प्रदान नहीं करता है, इसलिए यह अकेले अनुशंसित नहीं है । AEAD उद्देश्यों के लिए, संबंधित कुंजी हमलों से बचने के लिए, एक सामान्य एन्क्रिप्शन कुंजी के रूप में लंबे समय तक कम से कम दो बार एक रहस्य का उपयोग करने की आवश्यकता होती है: पहली छमाही एन्क्रिप्शन कुंजी के रूप में कार्य करती है, और दूसरी छमाही अखंडता जांच के लिए कुंजी के रूप में कार्य करती है। (अर्थात्, इस मामले में, एक पासवर्ड और नमक से एक ही रहस्य उत्पन्न करते हैं, और दो में उस रहस्य को विभाजित करते हैं।)

जावा कार्यान्वयन

कार्यान्वयन में विभिन्न कार्य एक विशिष्ट प्रदाता, अर्थात् "बीसी" का उपयोग करते हैं, इसके एल्गोरिदम के लिए। सामान्य तौर पर, हालांकि, विशिष्ट प्रदाताओं से अनुरोध करने की अनुशंसा नहीं की जाती है, क्योंकि सभी प्रदाता सभी जावा कार्यान्वयन पर उपलब्ध नहीं हैं, चाहे समर्थन की कमी के लिए, कोड दोहराव से बचने के लिए, या अन्य कारणों से। यह सलाह विशेष रूप से 2018 की शुरुआत में एंड्रॉइड पी पूर्वावलोकन के जारी होने के बाद से महत्वपूर्ण हो गई है, क्योंकि "बीसी" प्रदाता से कुछ कार्यक्षमता को वहां हटा दिया गया है - एंड्रॉइड डेवलपर्स ब्लॉग में "एंड्रॉइड पी में क्रिप्टोग्राफी परिवर्तन" लेख देखें। ओरेकल प्रोवाइडर्स का परिचय भी देखें ।

इस प्रकार, PROVIDERमौजूद नहीं होना चाहिए और स्ट्रिंग -BCको हटा दिया जाना चाहिए PBE_ALGORITHM। इस संबंध में कार्यान्वयन 2 सही है।

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

SecureRandom Android में

जैसा कि एंड्रॉइड डेवलपर्स ब्लॉग में "कुछ सिक्योर रैंडम विचार" लेख में विस्तृत है, java.security.SecureRandom2013 से पहले एंड्रॉइड रिलीज़ के कार्यान्वयन में एक दोष है जो इसे डिलीवर करने वाले यादृच्छिक संख्याओं की ताकत को कम करता है। जैसा कि उस लेख में वर्णित है, इस दोष को कम किया जा सकता है।


वह डबल सीक्रेट जनरेशन मेरी राय में थोड़ी बेकार है, आप आसानी से जनरेट किए गए सीक्रेट को दो में विभाजित कर सकते हैं, या - यदि पर्याप्त बिट उपलब्ध नहीं हैं - एक काउंटर (पहली कुंजी के लिए 1, दूसरी कुंजी के लिए 2) जोड़ें गुप्त और एकल हैश प्रदर्शन करते हैं। सभी पुनरावृत्तियों को दो बार करने की आवश्यकता नहीं है।
मार्टन बॉड्यूज

HMAC और नमक की जानकारी के लिए धन्यवाद। मैं इस समय HMAC का उपयोग नहीं करूंगा लेकिन बाद में यह बहुत उपयोगी हो सकता है। और सामान्य तौर पर, यह एक अच्छी बात है, इसमें कोई संदेह नहीं है।
कांव-कांव

सभी एडिट के लिए बहुत बहुत धन्यवाद और यह (अब) जावा में एईएस एन्क्रिप्शन के लिए अद्भुत परिचय!
कांव-कांव

1
यह होना चाहिए। getInstanceएक अधिभार है जो केवल एल्गोरिथ्म का नाम लेता है। उदाहरण: Cipher.getInstance () बाउंसी कैसल सहित कई प्रदाताओं को जावा कार्यान्वयन में पंजीकृत किया जा सकता है और इस तरह का अधिभार उनमें से एक के लिए प्रदाताओं की सूची को खोजता है जो दिए गए एल्गोरिदम को लागू करता है। आपको इसे आजमाना चाहिए और देखना चाहिए।
पीटर ओ।

1
Yup, यह Security.getProviders () द्वारा दिए गए क्रम में प्रदाताओं को खोजेगा - हालाँकि अब यह भी जाँच करेगा कि कुंजी प्रदाता द्वारा init () कॉल के दौरान हार्डवेयर असिस्टेड एन्क्रिप्शन की अनुमति देता है या नहीं। यहाँ अधिक विवरण: docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/…
मार्टन बोदवेस

18

# 2 का कभी भी उपयोग नहीं किया जाना चाहिए क्योंकि यह सिफर के लिए केवल "एईएस" (जिसका अर्थ है टेक्स्ट पर ईसीबी मोड एन्क्रिप्शन, एक बड़ा नो-नो) का उपयोग करता है। मैं सिर्फ # 1 की बात करूंगा।

पहला कार्यान्वयन एन्क्रिप्शन के लिए सर्वोत्तम प्रथाओं का पालन करना प्रतीत होता है। स्थिरांक आम तौर पर ठीक होते हैं, हालांकि PBE के प्रदर्शन के लिए नमक का आकार और पुनरावृत्तियों की संख्या दोनों पक्ष हैं। Futhermore, यह AES-256 के लिए लगता है क्योंकि PBE प्रमुख पीढ़ी 256 हार्ड कोडित मूल्य (उन सभी स्थिरांक के बाद एक शर्म) के रूप में 256 का उपयोग करता है। यह CBC और PKCS5Padding का उपयोग करता है जो कम से कम आप क्या उम्मीद करेंगे।

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

अपवाद हैंडलिंग और इनपुट सत्यापन बढ़ाया जा सकता है, अपवाद को पकड़ना मेरी पुस्तक में हमेशा गलत है। फरहटरमोर, आईसीट्रिप को लागू करता है, जिसे मैं नहीं जानता। मुझे पता है कि किसी वर्ग में साइड इफेक्ट्स के बिना केवल तरीके होना थोड़ा अजीब है। आम तौर पर, आप उन स्थैतिक बनाते हैं। सिफर इंस्टेंस आदि का कोई बफ़रिंग नहीं है, इसलिए प्रत्येक आवश्यक वस्तु को विज्ञापन-nauseum बनाया जाता है। हालाँकि, आप सुरक्षित रूप से ICrypto को उस परिभाषा से हटा सकते हैं, उस स्थिति में आप कोड को स्टैटिक विधियों में भी रिफलेक्टर कर सकते हैं (या इसे अधिक ऑब्जेक्ट ओरिएंटेड करने के लिए फिर से लिख सकते हैं, आपकी पसंद)।

समस्या यह है कि कोई भी आवरण हमेशा उपयोग के मामले के बारे में धारणा बनाता है। यह कहना कि एक आवरण सही है या गलत इसलिए चारपाई है। यही कारण है कि मैं हमेशा रैपर क्लास पैदा करने से बचने की कोशिश करता हूं। लेकिन कम से कम यह स्पष्ट रूप से गलत नहीं लगता है।


इस विस्तृत उत्तर के लिए आपका बहुत-बहुत धन्यवाद! मुझे पता है कि यह शर्म की बात है, लेकिन मुझे अभी तक कोड समीक्षा अनुभाग नहीं पता था: डी इस संकेत के लिए धन्यवाद, मैं इसकी जांच करूंगा। लेकिन यह सवाल भी मेरी राय में फिट बैठता है क्योंकि मैं इन कोड स्निपेट की समीक्षा नहीं करना चाहता। इसके बजाय, मैं आपसे पूछना चाहता हूं कि एंड्रॉइड में एईएस एन्क्रिप्शन को लागू करते समय कौन से पहलू महत्वपूर्ण हैं। और आप फिर से सही हैं, यह कोड स्निपेट AES-256 के लिए है। तो आप कहेंगे कि यह AES-256 का एक सामान्य कार्यान्वयन है? उपयोग का मामला यह है कि मैं केवल एक डेटाबेस में पाठ जानकारी को सुरक्षित रूप से संग्रहीत करना चाहता हूं।
caw

1
यह अच्छा लग रहा है, लेकिन अखंडता जांच और प्रमाणीकरण नहीं होने का विचार मुझे परेशान करेगा। यदि आपके पास पर्याप्त स्थान है, तो मैं गंभीरता से सिफरटेक्स्ट पर HMAC जोड़ने पर विचार करूंगा। उन्होंने कहा, जैसा कि आप शायद केवल गोपनीयता जोड़ने की कोशिश कर रहे हैं, मैं इसे एक बड़ा प्लस मानूंगा, लेकिन सीधे तौर पर आवश्यकता नहीं।
मार्टन बोडेवेस

लेकिन अगर इरादा केवल यह है कि दूसरों को एन्क्रिप्टेड जानकारी तक पहुंच नहीं होनी चाहिए, तो मुझे एचएमएसी की आवश्यकता नहीं है, है ना? यदि वे सिफरटेक्स्ट बदलते हैं और डिक्रिप्शन के "गलत" परिणाम को मजबूर करते हैं, तो कोई वास्तविक समस्या नहीं है, क्या कोई समस्या है?
caw

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

1
यदि आप अखंडता चाहते हैं तो एईएस इन गैलोज / काउंटर-मोड (एईएस-जीसीएम) का उपयोग क्यों नहीं करें?
किम्विस

1

आपने एक बहुत ही दिलचस्प सवाल पूछा है। सभी एल्गोरिदम के साथ सिफर कुंजी "गुप्त सॉस" है, क्योंकि एक बार जब वह जनता के लिए जाना जाता है, तो बाकी सब भी है। तो आप Google द्वारा इस दस्तावेज़ के तरीके देखें

सुरक्षा

Google इन-ऐप बिलिंग के अलावा सुरक्षा पर भी विचार दिया गया है जो आनंददायक है

billing_best_practices


इन लिंक्स के लिए धन्यवाद! क्या मतलब है जब आप "जब सिफर कुंजी बाहर है, बाकी सब भी बाहर है"?
caw

मेरा मतलब है कि एन्क्रिप्शन कुंजी को सुरक्षित करने की आवश्यकता है, अगर कोई भी उस पर पकड़ बना सकता है, तो आपका एन्क्रिप्टेड डेटा प्लेनटेक्स्ट जितना अच्छा है। कृपया अपवोट करें अगर आपको मेरा उत्तर कुछ हद तक उपयोगी लगा :-)
100rabh

0

BouncyCastle लाइटवेट एपीआई का उपयोग करें। यह PBE और नमक के साथ 256 AES प्रदान करता है।
यहां नमूना कोड, जो फ़ाइलों को एन्क्रिप्ट / डिक्रिप्ट कर सकता है।

public void encrypt(InputStream fin, OutputStream fout, String password) {
    try {
        PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(new SHA256Digest());
        char[] passwordChars = password.toCharArray();
        final byte[] pkcs12PasswordBytes = PBEParametersGenerator.PKCS12PasswordToBytes(passwordChars);
        pGen.init(pkcs12PasswordBytes, salt.getBytes(), iterationCount);
        CBCBlockCipher aesCBC = new CBCBlockCipher(new AESEngine());
        ParametersWithIV aesCBCParams = (ParametersWithIV) pGen.generateDerivedParameters(256, 128);
        aesCBC.init(true, aesCBCParams);
        PaddedBufferedBlockCipher aesCipher = new PaddedBufferedBlockCipher(aesCBC, new PKCS7Padding());
        aesCipher.init(true, aesCBCParams);

        // Read in the decrypted bytes and write the cleartext to out
        int numRead = 0;
        while ((numRead = fin.read(buf)) >= 0) {
            if (numRead == 1024) {
                byte[] plainTemp = new byte[aesCipher.getUpdateOutputSize(numRead)];
                int offset = aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
                final byte[] plain = new byte[offset];
                System.arraycopy(plainTemp, 0, plain, 0, plain.length);
                fout.write(plain, 0, plain.length);
            } else {
                byte[] plainTemp = new byte[aesCipher.getOutputSize(numRead)];
                int offset = aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
                int last = aesCipher.doFinal(plainTemp, offset);
                final byte[] plain = new byte[offset + last];
                System.arraycopy(plainTemp, 0, plain, 0, plain.length);
                fout.write(plain, 0, plain.length);
            }
        }
        fout.close();
        fin.close();
    } catch (Exception e) {
        e.printStackTrace();
    }

}

public void decrypt(InputStream fin, OutputStream fout, String password) {
    try {
        PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(new SHA256Digest());
        char[] passwordChars = password.toCharArray();
        final byte[] pkcs12PasswordBytes = PBEParametersGenerator.PKCS12PasswordToBytes(passwordChars);
        pGen.init(pkcs12PasswordBytes, salt.getBytes(), iterationCount);
        CBCBlockCipher aesCBC = new CBCBlockCipher(new AESEngine());
        ParametersWithIV aesCBCParams = (ParametersWithIV) pGen.generateDerivedParameters(256, 128);
        aesCBC.init(false, aesCBCParams);
        PaddedBufferedBlockCipher aesCipher = new PaddedBufferedBlockCipher(aesCBC, new PKCS7Padding());
        aesCipher.init(false, aesCBCParams);

        // Read in the decrypted bytes and write the cleartext to out
        int numRead = 0;
        while ((numRead = fin.read(buf)) >= 0) {
            if (numRead == 1024) {
                byte[] plainTemp = new byte[aesCipher.getUpdateOutputSize(numRead)];
                int offset = aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
                // int last = aesCipher.doFinal(plainTemp, offset);
                final byte[] plain = new byte[offset];
                System.arraycopy(plainTemp, 0, plain, 0, plain.length);
                fout.write(plain, 0, plain.length);
            } else {
                byte[] plainTemp = new byte[aesCipher.getOutputSize(numRead)];
                int offset = aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
                int last = aesCipher.doFinal(plainTemp, offset);
                final byte[] plain = new byte[offset + last];
                System.arraycopy(plainTemp, 0, plain, 0, plain.length);
                fout.write(plain, 0, plain.length);
            }
        }
        fout.close();
        fin.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

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

2
निर्भर करता है कि क्या आप साइड चैनल हमलों के खिलाफ सुरक्षा को शामिल करना चाहते हैं। आम तौर पर, आपको यह मान लेना चाहिए कि क्रिप्टोग्राफिक एल्गोरिदम को अपने दम पर लागू करना बहुत असुरक्षित है। जैसा कि एईएस सीबीसी ओरेकल के जावा रनटाइम लिबास में उपलब्ध है, संभवतः उन का उपयोग करना और बाउंसी कैसल पुस्तकालयों का उपयोग करना सबसे अच्छा है यदि एक एल्गोरिथ्म अनुपलब्ध है।
Maarten Bodewes

इसकी परिभाषा याद आ रही है buf(मुझे वास्तव में आशा है कि यह कोई staticक्षेत्र नहीं है )। यह भी दोनों की तरह दिखता है encrypt()और decrypt()अंतिम ब्लॉक को सही ढंग से संसाधित करने में विफल होगा यदि इनपुट 1024 बाइट्स का एक से अधिक है।
टीसी

0

मुझे यहाँ एक अच्छा कार्यान्वयन मिला: http://nelenkov.blogspot.fr/2012/04/using-password-based-enc एन्क्रिप्शन-on.html और https://github.com/nelenkov/android-pbe जो भी मददगार था Android के लिए एक अच्छा पर्याप्त एईएस कार्यान्वयन के लिए मेरी तलाश में

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