【问题标题】:I want to remove the secret information of a PrivateKey (sun.security.rsa.RSAPrivateCrtKeyImpl) from memory?我想从内存中删除 PrivateKey (sun.security.rsa.RSAPrivateCrtKeyImpl) 的秘密信息?
【发布时间】:2015-10-20 16:17:22
【问题描述】:

我有一些 Java 代码生成一个实现接口 java.security.PrivateKey 的类的实例(实际对象是 sun.security.rsa.RSAPrivateCrtKeyImpl 的一个实例)。此代码的目的是生成一个 PrivateKey,然后将其拆分为共享(密钥的分割),然后将共享存储在智能卡上。共享部分工作正常,我的问题是如何处理不再需要的 PrivateKey。

要求 PrivateKey 信息(应保密)在拆分为共享后应尽快从内存中删除。

接口 PrivateKey 扩展了接口 Destroyable,但我没有看到 Destroyable 的方法在任何地方实现(它必须在此层次结构中的某个地方实现)。但是,如果我在我拥有的 PrivateKey(这是一个 RSAPrivateCrtKeyImpl)上调用 destroy,那么它会引发 javax.security.auth.DestroyFailedException。

我拥有的对象似乎完全不可变,有没有办法覆盖对象中的字段?例如将它们设置为零?或者应该遵循什么方法从内存中删除这些秘密的不可变对象?谢谢!

【问题讨论】:

    标签: memory cryptography jvm rsa private-key


    【解决方案1】:

    是的,您可以使用reflection
    我创建了一个简单的代码,您可以使用它来销毁关键信息:

    public static void destroyRSAKey(sun.security.rsa.RSAPrivateCrtKeyImpl key) throws NoSuchFieldException, SecurityException {
        destroyBigInteger(key.getModulus());
        destroyBigInteger(key.getPublicExponent());
        destroyBigInteger(key.getPrivateExponent());
        destroyBigInteger(key.getPrimeP());
        destroyBigInteger(key.getPrimeQ());
        destroyBigInteger(key.getPrimeExponentP());
        destroyBigInteger(key.getPrimeExponentQ());
        destroyBigInteger(key.getCrtCoefficient());
    }
        
    public static final void destroyBigInteger(java.math.BigInteger destroyThis) {
        try {
            java.lang.reflect.Field f = java.math.BigInteger.class.getDeclaredField("mag");
            f.setAccessible(true);
            f.set(destroyThis, new int[] { 0 });
            f.setAccessible(false);
            f = java.math.BigInteger.class.getDeclaredField("signum");
            f.setAccessible(true);
            f.setInt(destroyThis, 0);
            f.setAccessible(false);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
    

    【讨论】:

      【解决方案2】:

      不,你不能。密钥创建的 Java 软件实现使用BigInteger,这确实是不可变的。您可能已经发现Destroyable.destroy 方法仅在少数类中实现。从 Java 7 开始,这些是直接实现的类:

      KerberosKey, KerberosTicket, KeyStore.PasswordProtection, X500PrivateCredential
      

      我猜这些类确实实现了Destroyable.destroy,但其他所有类都没有。

      因此,您唯一能做的就是依靠垃圾收集器和可能的操作系统来清理和/或覆盖BigInteger 实例。请注意,当使用私钥时,您会遇到同样的问题。


      如果您已经拥有智能卡,我建议您使用智能卡来生成和拆分密钥。在内部生成密钥,然后使用对称 AES 密钥加密密钥,拆分 AES 密钥并将包装的 RSA 密钥和(2 个剩余的)密钥部分从智能卡中传输出来。 Usually XOR is used 而不是按字面拆分密钥。

      【讨论】:

        【解决方案3】:

        编辑 如上所述,java.security.PrivateKey.destroy() 未在 Java 8 中实现,这是部署 RSA 算法时 Sun Java 运行时环境严重安全漏洞

        基于 Doomny 58 的解决方案,我得到了一个实际运行的方法destroyPrivateRSAKey(),并进行了适当的内容销毁;任何错误都会映射到DestroyFailedException,因此当调用成功时,您可以确定私有 RSA 参数会被销毁。

        /**
             * Destroy data of a BigInteger
             * 
             * @param destroyThis [in] BigIntegeer onject to destroy
             * @throws DestroyFailedException on any error
             */
            public static final void destroyBigInteger(java.math.BigInteger destroyThis) throws DestroyFailedException
            {
                if (destroyThis == null)
                {
                    return;
                }
                try
                {
                    // Retrieve buffer field 'mag', overwrite with 0-s and set to {0}
                    java.lang.reflect.Field f = java.math.BigInteger.class.getDeclaredField("mag");
                    f.setAccessible(true);
                    int[] mag = (int[]) f.get(destroyThis);
                    if (mag != null)
                    {
                        java.util.Arrays.fill(mag, 0);
                    }
                    f.set(destroyThis, new int[] { 0 });
                    f.setAccessible(false);
        
                    // set field signum = 0
                    f = java.math.BigInteger.class.getDeclaredField("signum");
                    f.setAccessible(true);
                    f.setInt(destroyThis, 0);
                    f.setAccessible(false);
                }
                catch (Throwable e)
                {
                    e.printStackTrace();
                    throw new DestroyFailedException();
                }
            }
        
            /**
             * Get BigInteger member of an object with spec'd accesor method
             * @param o [in] The object 
             * @param accessor [in] Name of the accessor method
             * @return The BigInteger
             * @throws DestroyFailedException on any error
             */
            private static BigInteger accessBIF(Object o, String accessor) throws DestroyFailedException
            {
                try
                {
                    Class<?> cls = o.getClass();
                    Method m = cls.getDeclaredMethod(accessor);
                    m.setAccessible(true);
                    BigInteger res = (BigInteger) m.invoke(o);
                    m.setAccessible(false);
                    return res;
                }
                catch (Throwable x)
                {
                    x.printStackTrace();
                    throw new DestroyFailedException();
                }
            }
        
            /**
             * Destroy BigInteger member
             * 
             * @param o        [in] Object with BigInteger
             * @param accessor [in] Member Accessor method
             * @throws DestroyFailedException
             */
            private static void destroyBIF(Object o, String accessor) throws DestroyFailedException
            {
                destroyBigInteger(accessBIF(o, accessor));
            }
        
            /**
             * Destroy Private RSA Key
             * 
             * @param key [in] A sun.security.rsa.RSAPrivateCrtKeyImpl
             * @throws DestroyFailedException
             */
            public static void destroyPrivateRSAKey(Object key) throws DestroyFailedException
            {
                destroyBIF(key, "getModulus");
                destroyBIF(key, "getPublicExponent");
                destroyBIF(key, "getPrivateExponent");
                destroyBIF(key, "getPrimeP");
                destroyBIF(key, "getPrimeQ");
                destroyBIF(key, "getPrimeExponentP");
                destroyBIF(key, "getPrimeExponentQ");
                destroyBIF(key, "getCrtCoefficient");
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-12
          • 1970-01-01
          • 2015-05-30
          • 2017-09-30
          • 1970-01-01
          相关资源
          最近更新 更多