2011-08-25 8 views
6

क्या निम्नलिखित जावा कोड स्मृति में गुप्त कुंजी को साफ़ करने के लिए पर्याप्त है (इसके सभी बाइट मान को 0 पर सेट करना)?जावा में एक गुप्त कुंजी कैसे शून्य है?

zerorize(SecretKey key) 
{ 
    byte[] rawKey = key.getEncoded(); 
    Arrays.fill(rawKey, (byte) 0); 
} 

दूसरे शब्दों में, getEncoded विधि वास्तविक कुंजी की एक प्रति या संदर्भ वापसी करता है? अगर एक प्रति वापस आती है, तो मैं सुरक्षा उपाय के रूप में गुप्त कुंजी को कैसे साफ़ कर सकता हूं?

उत्तर

-1

दूसरे शब्दों में, getEncoded विधि वास्तविक कुंजी की एक प्रति या संदर्भ वापसी करता है?

key.getEncoded() एक सरणी के लिए एक संदर्भ वापस आ जाएगी।

कुंजी की सामग्री को खारिज कर दिया है, तो जब आप Array.fill या नहीं, कुंजी लौटे सरणी द्वारा समर्थित है पर निर्भर करता है है। प्रलेखन को देखते हुए, ऐसा लगता है कि कुंजी के एन्कोडिंग कुंजी का एक और प्रतिनिधित्व है, यानी, कुंजी लौटाई गई सरणी द्वारा समर्थित नहीं है।

हालांकि यह पता लगाना आसान है। निम्नलिखित का प्रयास करें: उत्पादन false है

byte[] rawKey = key.getEncoded(); 
Arrays.fill(rawKey, (byte) 0); 

byte[] again = key.getEncoded(); 
Log.d(Arrays.equals(rawKey, again)); 

हैं, तो आप जानते हैं कि कुंजी अभी भी SecretKey में संग्रहित है।

-1

आदिम मूल्यों को छोड़कर, जावा में बाकी सब कुछ हमेशा संदर्भ द्वारा पारित किया जाता है, जिसमें सरणी भी शामिल है, इसलिए हाँ, आप दिए गए बाइट सरणी को सही ढंग से साफ़ कर रहे हैं।

हालांकि, गुप्तकी कक्षा शायद उस बाइट सरणी को उत्पन्न करने के लिए आवश्यक डेटा रखती है, जिसमें अंततः दिए गए बाइट सरणी की एक और प्रति शामिल है, इसलिए आपको जांच करनी चाहिए कि उस डेटा को कैसे साफ़ किया जाए।

+4

-1: * जावा में बाकी सब कुछ हमेशा संदर्भ द्वारा पारित किया जाता है * - Nooo, जावा * हमेशा * मूल्य से गुजरता है! कारण से आप * ऑब्जेक्ट * पास नहीं कर सकते हैं, क्योंकि कोई चर किसी ऑब्जेक्ट को पहले स्थान पर नहीं रख सकता है! – aioobe

+0

@aioobe .. आप सुनिश्चित हैं कि हम एक ही जावा के बारे में बात कर रहे हैं? int मूल्य से गुजरता है, बूलियन मूल्य से गुजरता है, इंटीजर एक संदर्भ है, साथ ही किसी ऑब्जेक्ट, सरणी इत्यादि ... जावा "एक मान" पास करता है, जो वास्तव में किसी ऑब्जेक्ट के लिए "संदर्भ" है, इसलिए यह है संदर्भ। –

+0

@ जोचिम .. मैं "दिए गए बाइट सरणी" का जिक्र कर रहा था, हालांकि आगे स्पष्ट किया कि एक और प्रतिलिपि हो सकती है। –

0

मुझे पूरा यकीन है कि rawKey साफ़ करने से key में डेटा प्रभावित नहीं होगा।

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

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

6

कुंजी को साफ़ करने का प्रयास करने से पहले, आपको पहले जांच करनी चाहिए कि SecretKey इंटरफ़ेस का कार्यान्वयन javax.security.auth.Destroyable इंटरफ़ेस लागू करता है। यदि ऐसा है, तो निश्चित रूप से पसंद करते हैं।

+0

केवल 1.8+ में काम करता है और आमतौर पर केवल DestroyFailedException –

-2

, एक अलग कील ले रहा है एक बार आप स्मृति अधिलेखित करने का सही क्षेत्र की पहचान की है, तो आप इसे एक बार से अधिक कार्य करना चाहेंगे:

zerorize(SecretKey key) 
{ 
    byte[] rawKey = key.getEncoded(); 
    Arrays.fill(rawKey, (byte) 0xFF); 
    Arrays.fill(rawKey, (byte) 0xAA); 
    Arrays.fill(rawKey, (byte) 0x55); 
    Arrays.fill(rawKey, (byte) 0x00); 
} 
0

कचरा कलेक्टर शक्ति, किसी एक प्रौद्योगिकी के आधार पर किसी भी समय भौतिक स्मृति में ऑब्जेक्ट को स्थानांतरित किया जा सकता है (यानी कॉपी किया गया), इसलिए आप यह सुनिश्चित नहीं कर सकते कि आप वास्तव में सरणी को शून्य करके कुंजी को नष्ट कर देंगे - यह मानते हुए कि आप "सर" को एक्सेस कर सकते हैं जिसमें कुंजी है, न कि इसकी प्रतिलिपि बनाएँ।

छोटे शब्दों में: यदि आपका सुरक्षा मॉडल और संदर्भ शून्यिंग कुंजी के लिए कॉल करता है, तो आपको जावा का उपयोग बिल्कुल नहीं करना चाहिए (या सी और असेंबली के अलावा कुछ भी नहीं)।

+0

फेंकता है, लेकिन यदि आपको जावा का उपयोग करना है, तो जीसी डेटा को दोबारा करने की संभावना है या ओएस इसे स्वैप करने के लिए आगे बढ़ने से पहले, –

3

getEncoded() ज्यादातर (उदाहरण के लिए javax.security.auth.kerberos के ओरेकल 1.6 स्रोत से) कुंजी का क्लोन वापस जाने के लिए लगता है:

public final byte[] getEncoded() { 
    if (destroyed) 
    throw new IllegalStateException("This key is no longer valid"); 
    return (byte[])keyBytes.clone(); 
} 

इसलिए वापसी डेटा पोंछते स्मृति से कुंजी की सभी प्रतियों को मिटाना नहीं है।

public void destroy() throws DestroyFailedException { 
    if (!destroyed) { 
    destroyed = true; 
    Arrays.fill(keyBytes, (byte) 0); 
    } 
} 

अजीब पर्याप्त ऐसा लगता है कि सभी मुख्य कार्यान्वयन javax.security.auth.Destroyable को लागू नहीं करते:

SecretKey से कुंजी साफ करने के लिए एक ही रास्ता javax.security.auth.Destroyable करने के लिए इसे डाली अगर यह इंटरफ़ेस लागू करता है और destroy() विधि आह्वान करने के लिए है । com.sun.crypto.provider.DESedeKey एईएस के लिए उपयोग नहीं किया गया है और न ही javax.crypto.spec.SecretKeySpec करता है। इन दोनों महत्वपूर्ण कार्यान्वयनों ने getEncoded विधि में कुंजी को क्लोन भी किया है। तो ऐसा लगता है कि इन बहुत ही आम एल्गोरिदम 3 डीईईएस और एईएस के लिए हमारे पास गुप्त कुंजी के लिए स्मृति को मिटा देने का कोई तरीका नहीं है?

1

GetEncoded गुप्त कुंजी की एक प्रति लौटाता है (इसलिए गुप्त कुंजी डेटा पर कोई प्रभाव नहीं पड़ता है), और डिफ़ॉल्ट रूप से नष्ट हो जाता है DestroyFailedException जो बेकार से भी बदतर है। यह केवल 1.8+ में उपलब्ध है, इसलिए एंड्रॉइड भाग्य से बाहर है। यहां एक हैक है जो आत्मनिरीक्षण का उपयोग करता है (1) उपलब्ध होने पर विनाश का आह्वान करता है और अपवाद नहीं फेंकता है, अन्यथा (2) कुंजी डेटा शून्य और शून्य को संदर्भ सेट करें।

package kiss.cipher; 

import java.lang.reflect.Field; 
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.util.Arrays; 

import javax.crypto.spec.SecretKeySpec; 

/** 
* Created by wmacevoy on 10/12/16. 
*/ 
public class CloseableKey implements AutoCloseable { 

    // forward portable to JDK 1.8 to destroy keys 
    // but usable in older JDK's 
    static final Method DESTROY; 
    static final Field KEY; 

    static { 
     Method _destroy = null; 

     Field _key = null; 
     try { 
      Method destroy = SecretKeySpec.class.getMethod("destroy"); 
      SecretKeySpec key = new SecretKeySpec(new byte[16], "AES"); 
      destroy.invoke(key); 
      _destroy = destroy; 
     } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { 
     } 

     try { 
      _key = SecretKeySpec.class.getDeclaredField("key"); 
      _key.setAccessible(true); 
     } catch (NoSuchFieldException | SecurityException ex) { 
     } 

     DESTROY = _destroy; 
     KEY = _key; 
    } 

    static void close(SecretKeySpec secretKeySpec) { 
     if (secretKeySpec != null) { 
      if (DESTROY != null) { 
       try { 
        DESTROY.invoke(secretKeySpec); 
       } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { 
        throw new IllegalStateException("inconceivable: " + ex); 
       } 
      } else if (KEY != null) { 
       try { 
        byte[] key = (byte[]) KEY.get(secretKeySpec); 
        Arrays.fill(key, (byte) 0); 
        KEY.set(secretKeySpec, null); 
       } catch (IllegalAccessException | IllegalArgumentException ex) { 
        throw new IllegalStateException("inconceivable: " + ex); 
       } 
      } 
     } 
    } 

    public final SecretKeySpec secretKeySpec; 

    CloseableKey(SecretKeySpec _secretKeySpec) { 

     secretKeySpec = _secretKeySpec; 
    } 

    @Override 
    public void close() { 
     close(secretKeySpec); 
    } 
} 

तरीका यह उपयोग करने के लिए

तरह
try (CloseableKey key = 
     new CloseableKey(new SecretKeySpec(data, 0, 16, "AES"))) { 
    aesecb.init(Cipher.ENCRYPT_MODE, key.secretKeySpec); 
} 

मैं closeable इंटरफ़ेस का उपयोग क्योंकि destroyable केवल एक 1.8+ सुविधा है। यह संस्करण 1.7+ पर काम करता है और यह बहुत ही कुशल है (यह एक परीक्षण पर एक परीक्षण को नष्ट करता है ताकि इसे कभी भी इसका उपयोग करने का फैसला किया जा सके)।

+0

यह एक हैक है, और जीसी मेमोरी या ओएस मूव डेटा को स्वैप करने के लिए रीपैक कर सकता है जो कुंजी डेटा रिसाव कर सकता है। एक जीसी या ओएस साइड इफेक्ट के कारण लीक होने की संभावना को कम करने के लिए जितनी जल्दी हो सके कुंजी को बंद करें। –

संबंधित मुद्दे