स्ट्रिंग और वाइस वर्सा में गुप्त कुंजी परिवर्तित करना


102

मैं एक कुंजी उत्पन्न कर रहा हूं और इसे DB में संग्रहीत करने की आवश्यकता है, इसलिए मैं इसे एक स्ट्रिंग में परिवर्तित करता हूं, लेकिन स्ट्रिंग से कुंजी प्राप्त करने के लिए। इसे पूरा करने के संभावित तरीके क्या हैं?

मेरा कोड है,

SecretKey key = KeyGenerator.getInstance("AES").generateKey();
String stringKey=key.toString();
System.out.println(stringKey);

मैं स्ट्रिंग से कुंजी वापस कैसे प्राप्त कर सकता हूं?


1
ध्यान दें कि स्ट्रिंग के लिए कुंजियों का रूपांतरण केवल तभी किया जाना चाहिए जब बिल्कुल आवश्यक हो। Stringजावा में उदाहरणों को नष्ट करने के लिए कोई स्पष्ट तरीका नहीं है, जबकि प्रमुख वस्तुओं और बाइट सरणियों को साफ किया जा सकता है। इसका मतलब यह है कि चाबियाँ लंबे समय तक मेमोरी के भीतर उपलब्ध रह सकती हैं। पासवर्ड (संरक्षित पासवर्ड) का उपयोग करना KeyStore, अधिमानतः रनटाइम सिस्टम / ओएस या यहां तक ​​कि हार्डवेयर द्वारा समर्थित होना चाहिए।
मार्टन बॉड्यूज

जवाबों:


272

आप SecretKeyएक बाइट सरणी ( byte[]) में कनवर्ट कर सकते हैं , फिर बेस 64 एनकोड करता है कि ए String। वापस a में कनवर्ट करने के लिए SecretKey, Base64 स्ट्रिंग को डीकोड करता है और इसे SecretKeySpecअपने मूल के पुनर्निर्माण के लिए उपयोग करता है SecretKey

जावा 8 के लिए

स्ट्रिंग के लिए गुप्त:

// create new key
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
// get base64 encoded version of the key
String encodedKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());

सीक्रेट के लिए स्ट्रिंग:

// decode the base64 encoded string
byte[] decodedKey = Base64.getDecoder().decode(encodedKey);
// rebuild key using SecretKeySpec
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES"); 

जावा 7 और उससे पहले (Android सहित):

नोट I: आप बेस 64 एन्कोडिंग / डिकोडिंग भाग को छोड़ सकते हैं और सिर्फ byte[]SQLite में स्टोर कर सकते हैं । यह कहा, Base64 एन्कोडिंग / डिकोडिंग प्रदर्शन एक महंगा ऑपरेशन नहीं है और आप बिना किसी समस्या के लगभग किसी भी DB में स्ट्रिंग्स को स्टोर कर सकते हैं।

नोट II: पहले के जावा संस्करणों में किसी एक java.langया java.utilपैकेज में Base64 शामिल नहीं है। हालांकि Apache Commons Codec , Bouncy Castle या Guava से कोडेक्स का उपयोग करना संभव है ।

स्ट्रिंग के लिए गुप्त:

// CREATE NEW KEY
// GET ENCODED VERSION OF KEY (THIS CAN BE STORED IN A DB)

    SecretKey secretKey;
    String stringKey;

    try {secretKey = KeyGenerator.getInstance("AES").generateKey();}
    catch (NoSuchAlgorithmException e) {/* LOG YOUR EXCEPTION */}

    if (secretKey != null) {stringKey = Base64.encodeToString(secretKey.getEncoded(), Base64.DEFAULT)}

सीक्रेट के लिए स्ट्रिंग:

// DECODE YOUR BASE64 STRING
// REBUILD KEY USING SecretKeySpec

    byte[] encodedKey     = Base64.decode(stringKey, Base64.DEFAULT);
    SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");

@Jabari क्या के लिए "Base64" वर्ग पैकेज है
स्वैप एल

@SwapL यह android.util.Base64 है। इस लिंक को देखें: developer.android.com/reference/android/util/Base64.html
जाबरी

@ MaartenBodewes-owlstead अधिकांश लोग अभी तक जावा 8 का उपयोग नहीं कर रहे हैं। मैंने एंड्रॉइड में इसका उपयोग किया, जो निश्चित रूप से 8 पर अभी तक नहीं है (और शायद कुछ समय के लिए नहीं होगा)। कृपया संदर्भ की धारणा पर किसी के उत्तर को संपादित न करें।
जाबरी

@ MaartenBodewes-owlstead आपकी टिप्पणी मेरे पहले वाक्य को पूरी तरह से नजरअंदाज करती है: "अधिकांश लोग अभी तक जावा 8 का उपयोग नहीं कर रहे हैं"। आपका उत्तर जावा उपयोगकर्ताओं, एंड्रॉइड और गैर-एंड्रॉइड के समान बहुमत के लिए अपवाद त्रुटियों को फेंक देगा। उस ने कहा, वर्तमान उत्तर के अलावा स्निपेट जोड़ने का आपका सुझाव अधिक संपूर्ण समाधान प्रदान करेगा। FYI करें, मैं अपने जवाब के संबंध में "भावुक" नहीं हूँ। तथ्य की बात के रूप में, मैंने एईएस के लिए डेस को स्वैप किया क्योंकि यह एक निश्चित सुधार सुरक्षा वार है (साथ ही मूल प्रश्न में कोड के अनुरूप अधिक है)।
जबरी

@ MaartenBodewes- उल्लू का पट्ठा ... फिर जो आपने जोड़ा वह "NoSuchAlgorithmException" अपवाद त्रुटियों को फेंक देगा। कृपया देखें: docs.oracle.com/javase/7/docs/api/javax/crypto/… मैं ठीक कर दूंगा ...
जबरी

5

यह दिखाने के लिए कि कुछ फ़ंक्शंस बनाने में कितना मज़ा आता है जो तेजी से विफल हो जाते हैं मैंने निम्नलिखित 3 फ़ंक्शंस लिखे हैं।

एक एईएस कुंजी बनाता है, एक इसे एनकोड करता है और एक इसे वापस डिकोड करता है। इन तीन विधियों का उपयोग जावा 8 (आंतरिक कक्षाओं या बाहर की निर्भरता के बिना) के साथ किया जा सकता है:

public static SecretKey generateAESKey(int keysize)
        throws InvalidParameterException {
    try {
        if (Cipher.getMaxAllowedKeyLength("AES") < keysize) {
            // this may be an issue if unlimited crypto is not installed
            throw new InvalidParameterException("Key size of " + keysize
                    + " not supported in this runtime");
        }

        final KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(keysize);
        return keyGen.generateKey();
    } catch (final NoSuchAlgorithmException e) {
        // AES functionality is a requirement for any Java SE runtime
        throw new IllegalStateException(
                "AES should always be present in a Java SE runtime", e);
    }
}

public static SecretKey decodeBase64ToAESKey(final String encodedKey)
        throws IllegalArgumentException {
    try {
        // throws IllegalArgumentException - if src is not in valid Base64
        // scheme
        final byte[] keyData = Base64.getDecoder().decode(encodedKey);
        final int keysize = keyData.length * Byte.SIZE;

        // this should be checked by a SecretKeyFactory, but that doesn't exist for AES
        switch (keysize) {
        case 128:
        case 192:
        case 256:
            break;
        default:
            throw new IllegalArgumentException("Invalid key size for AES: " + keysize);
        }

        if (Cipher.getMaxAllowedKeyLength("AES") < keysize) {
            // this may be an issue if unlimited crypto is not installed
            throw new IllegalArgumentException("Key size of " + keysize
                    + " not supported in this runtime");
        }

        // throws IllegalArgumentException - if key is empty
        final SecretKeySpec aesKey = new SecretKeySpec(keyData, "AES");
        return aesKey;
    } catch (final NoSuchAlgorithmException e) {
        // AES functionality is a requirement for any Java SE runtime
        throw new IllegalStateException(
                "AES should always be present in a Java SE runtime", e);
    }
}

public static String encodeAESKeyToBase64(final SecretKey aesKey)
        throws IllegalArgumentException {
    if (!aesKey.getAlgorithm().equalsIgnoreCase("AES")) {
        throw new IllegalArgumentException("Not an AES key");
    }

    final byte[] keyData = aesKey.getEncoded();
    final String encodedKey = Base64.getEncoder().encodeToString(keyData);
    return encodedKey;
}

2
ध्यान दें कि कुंजी स्टोर एक हार्डवेयर सुरक्षा मॉड्यूल (या किसी अन्य स्थान पर जहां getEncoded()उपलब्ध नहीं है) पर स्टोर करने / प्राप्त करने की कुंजी काम नहीं कर सकती है ।
Maarten Bodewes

1

वास्तव में लुइस ने जो प्रस्ताव दिया वह मेरे काम नहीं आया। मुझे एक और तरीका निकालना था। इससे मुझे मदद मिली। आपकी भी मदद कर सकते हैं। लिंक:

  1. * .getEncoded (): https://docs.oracle.com/javase/7/docs/api/java/security/Key.html

  2. एनकोडर जानकारी: https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Encoder.html

  3. विकोडक जानकारी: https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Decoder.html

कोड स्निपेट: एन्कोडिंग के लिए:

String temp = new String(Base64.getEncoder().encode(key.getEncoded()));

डिकोडिंग के लिए:

byte[] encodedKey = Base64.getDecoder().decode(temp);
SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "DES");

0

आप उपयोग नहीं करना चाहते हैं .toString()

ध्यान दें कि सीक्रेटके को java.security.Key से विरासत में मिला है, जो खुद सीरियल से विरासत में मिला है। तो यहाँ कुंजी (कोई भी इरादा नहीं है) कुंजी को बाइटएयरऑयूटपुटस्ट्रीम में क्रमबद्ध करना है, बाइट प्राप्त करें [] सरणी और इसे डीबी में स्टोर करें। रिवर्स प्रक्रिया बाइट पाने के लिए होगी [] डीबी से सरणी, एक बाइटएयरएयरप्यूटस्ट्रीम का बाइट बाइट [] एरे से बनाएं, और सीक्रेटरी को इसे बंद कर दें ...

... या यहां तक ​​कि सरल, बस .getEncoded()java.security.Key से विरासत में मिली विधि का उपयोग करें (जो कि सीक्रेटकेयर का एक मूल इंटरफ़ेस है)। यह विधि कुंजी / सेक्रेटरी से एन्कोडेड बाइट [] सरणी को वापस कर देती है, जिसे आप डेटाबेस से स्टोर या पुनः प्राप्त कर सकते हैं।

यह सब मान रहा है कि आपका SecretKey कार्यान्वयन एन्कोडिंग का समर्थन करता है। अन्यथा, getEncoded()अशक्त लौट आएगा।

संपादित करें:

आपको की / सीक्रेटके जेवाडॉक्स (एक गूगल पेज की शुरुआत में उपलब्ध) को देखना चाहिए:

http://download.oracle.com/javase/6/docs/api/java/security/Key.html

या यह CodeRanch से (उसी Google खोज के साथ भी पाया गया):

http://www.coderanch.com/t/429127/java/java/Convertion-between-SecretKey-String-or


जब भी आपके पास वैकल्पिक दृष्टिकोण होता है, तो इन दिनों सीरियलाइज़ेशन एक विरोधी पैटर्न है। स्वीकृत जवाब जो बेस 64 को एनकोड और डीकोड करता है, वह कहीं बेहतर है।
user2223059

0

स्ट्रिंग और इसके विपरीत करने के लिए SecretKeySpec को परिवर्तित करना: आप उस getEncoded()पद्धति का उपयोग कर सकते हैं SecretKeySpecजिसमें वह देगा byteArray, जिससे आप ऑब्जेक्ट में मान encodeToString()प्राप्त करने के लिए उपयोग कर सकते हैं ।stringSecretKeySpecBase64

परिवर्तित जबकि SecretKeySpecकरने के लिए String: उपयोग decode()में Base64दे देंगे byteArray, कि से आप के लिए उदाहरण बना सकते हैं SecretKeySpecपैरामीटर वाला के रूप में byteArrayअपने पुन: पेश करने SecretKeySpec

String mAesKey_string;
SecretKeySpec mAesKey= new SecretKeySpec(secretKey.getEncoded(), "AES");

//SecretKeySpec to String 
    byte[] byteaes=mAesKey.getEncoded();
    mAesKey_string=Base64.encodeToString(byteaes,Base64.NO_WRAP);

//String to SecretKeySpec
    byte[] aesByte = Base64.decode(mAesKey_string, Base64.NO_WRAP);
    mAesKey= new SecretKeySpec(aesByte, "AES");

-1

इसे आज़माएं, यह बिना Base64 के काम करता है (जो कि केवल JDK 1.8 में शामिल है), यह कोड पिछले जावा संस्करण में भी चलता है :)

private static String SK = "Secret Key in HEX";


//  To Encrupt

public static String encrypt( String Message ) throws Exception{

    byte[] KeyByte = hexStringToByteArray( SK);
    SecretKey k = new SecretKeySpec(KeyByte, 0, KeyByte.length, "DES");

    Cipher c = Cipher.getInstance("DES","SunJCE");
    c.init(1, k);
    byte mes_encrypted[] = cipher.doFinal(Message.getBytes());

    String MessageEncrypted = byteArrayToHexString(mes_encrypted);
    return MessageEncrypted;
}

//  To Decrypt

public static String decrypt( String MessageEncrypted )throws Exception{

    byte[] KeyByte = hexStringToByteArray( SK );
    SecretKey k = new SecretKeySpec(KeyByte, 0, KeyByte.length, "DES");

    Cipher dcr =  Cipher.getInstance("DES","SunJCE");
    dc.init(Cipher.DECRYPT_MODE, k);
    byte[] MesByte  = hexStringToByteArray( MessageEncrypted );
    byte mes_decrypted[] = dcipher.doFinal( MesByte );
    String MessageDecrypeted = new String(mes_decrypted);

    return MessageDecrypeted;
}

public static String byteArrayToHexString(byte bytes[]){

    StringBuffer hexDump = new StringBuffer();
    for(int i = 0; i < bytes.length; i++){
    if(bytes[i] < 0)
    {   
        hexDump.append(getDoubleHexValue(Integer.toHexString(256 - Math.abs(bytes[i]))).toUpperCase());
    }else
    {
        hexDump.append(getDoubleHexValue(Integer.toHexString(bytes[i])).toUpperCase());
    }
    return hexDump.toString();

}



public static byte[] hexStringToByteArray(String s) {

    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2)
    {   
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
    }
    return data;

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