alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (KeyDestructionTest.java)

This example Java source code file (KeyDestructionTest.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

crypto, destroyfailedexception, exception, illegalstateexception, keydestructiontest, keypair, mydestroyableprivatekey, mydestroyablesecretkey, nosuchalgorithmexception, not, override, rsa, security, string, unsupportedoperationexception, usable, util

The KeyDestructionTest.java Java example source code

/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * @test
 * @bug 6263419
 * @summary No way to clean the memory for a java.security.Key
 */

import java.security.*;
import java.util.*;
import javax.crypto.*;
import javax.security.auth.Destroyable;
import javax.security.auth.DestroyFailedException;

public class KeyDestructionTest {
    public static void main(String[] args) throws Exception {
        KeyPair keypair = generateKeyPair("RSA", 1024);

        // Check keys that support and have implemented key destruction
        testKeyDestruction(new MyDestroyableSecretKey());
        testKeyDestruction(new MyDestroyablePrivateKey());

        // Check keys that support but have not implemented key destruction
        testNoKeyDestruction(generateSecretKey("AES", 128));
        testNoKeyDestruction(keypair.getPrivate());

        // Check keys that do not support key destruction
        try {
            testKeyDestruction(keypair.getPublic());
        } catch (UnsupportedOperationException uoe) {
            // not an error
            System.out.println(keypair.getPublic().getClass().getName() +
                " keys do not support key destruction");
        }

        System.out.println("PASSED.");
    }

    // Check the behaviour of a key that implements key destruction
    private static void testKeyDestruction(Key key) throws Exception {
        String klass = key.getClass().getName();
        boolean hasUsable = key instanceof Usable;

        try {
            key.getAlgorithm();
            key.getFormat();
            if (allZero(key.getEncoded())) {
                throw new Exception("error: key destroyed prematurely");
            }
        } catch (IllegalStateException ise) {
            throw new Exception("error: unexpected ISE", ise);
        }

        if (hasUsable) {
            ((Usable) key).useKey();
        }

        destroyKey(key);

        try {
            if (hasUsable) {
                ((Usable) key).useKey();
            }
        } catch (IllegalStateException ise) {
            // not an error
        }

        try {
            key.getAlgorithm();
            key.getFormat();
            if (!allZero(key.getEncoded())) {
                throw new Exception("error: key destroyed incorrectly");
            }
        } catch (IllegalStateException ise) {
            // not an error
        }

        System.out.println("A " + klass +
            " key has been successfully destroyed");
    }

    // Check the behaviour of a key that does not implement key destruction
    private static void testNoKeyDestruction(Destroyable key)
        throws Exception {
        String klass = key.getClass().getName();

        if (key.isDestroyed()) {
            throw new Exception("error: a " + klass +
                " key has been unexpectedly destroyed");
        }
        try {
            key.destroy();
        } catch (DestroyFailedException dfe) {
            // not an error

            if (key.isDestroyed()) {
                throw new Exception("error: a " + klass +
                    " key has been unexpectedly destroyed");
            }
            System.out.println(klass + " keys are not destroyable");
            return;
        }
        throw new Exception("error: key may been unexpectedly destroyed");
    }

    private static KeyPair generateKeyPair(String algorithm, int size)
        throws NoSuchAlgorithmException {
        KeyPairGenerator generator = KeyPairGenerator.getInstance(algorithm);
        generator.initialize(size);
        return generator.genKeyPair();
    }

    private static SecretKey generateSecretKey(String algorithm, int size)
        throws NoSuchAlgorithmException {
        KeyGenerator generator = KeyGenerator.getInstance(algorithm);
        generator.init(size);
        return generator.generateKey();
    }

    private static void destroyKey(Key key) throws Exception {
        String klass = key.getClass().getName();

        if (!(key instanceof Destroyable)) {
            throw new UnsupportedOperationException();
        }

        Destroyable dKey = (Destroyable) key;
        if (dKey.isDestroyed()) {
            throw new Exception("error: a " + klass +
                " key has already been destroyed");
        }
        dKey.destroy();
        if (!dKey.isDestroyed()) {
            throw new Exception("error: a " + klass +
                " key has NOT been destroyed");
        }
    }

    private static boolean allZero(byte[] bytes) {
        int count = 0;
        for (byte b : bytes) {
            if (b == 0x00) {
                count++;
            }
        }
        return (bytes.length == count);
    }
}

interface Usable {
    public void useKey();
}

class MyDestroyableSecretKey implements SecretKey, Usable {
    private byte[] encoded = new byte[]{0x0F, 0x1F, 0x2F, 0x3F}; // non-zero
    private boolean isDestroyed = false;

    @Override
    public void useKey() {
        if (isDestroyed) {
            throw new IllegalStateException();
        }
    }

    @Override
    public String getAlgorithm() {
        return "MyDestroyableSecretKey algorithm";
    }

    @Override
    public String getFormat() {
        return "MyDestroyableSecretKey format";
    }

    @Override
    public byte[] getEncoded() {
        return this.encoded;
    }

    @Override
    public void destroy() throws DestroyFailedException {
        if (!this.isDestroyed) {
            Arrays.fill(encoded, (byte) 0);
            this.isDestroyed = true;
        }
    }

    @Override
    public boolean isDestroyed() {
        return this.isDestroyed;
    }
}

class MyDestroyablePrivateKey implements PrivateKey, Usable {
    private byte[] encoded = new byte[]{0x4F, 0x5F, 0x6F, 0x7F}; // non-zero
    private boolean isDestroyed = false;

    @Override
    public void useKey() {
        if (isDestroyed) {
            throw new IllegalStateException();
        }
    }

    @Override
    public String getAlgorithm() {
        return "MyDestroyablePrivateKey algorithm";
    }

    @Override
    public String getFormat() {
        return "MyDestroyablePrivateKey format";
    }

    @Override
    public byte[] getEncoded() {
        return this.encoded;
    }

    @Override
    public void destroy() throws DestroyFailedException {
        if (!this.isDestroyed) {
            Arrays.fill(encoded, (byte) 0);
            this.isDestroyed = true;
        }
    }

    @Override
    public boolean isDestroyed() {
        return this.isDestroyed;
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java KeyDestructionTest.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.