co.mitro.keyczar.Util.java Source code

Java tutorial

Introduction

Here is the source code for co.mitro.keyczar.Util.java

Source

/*******************************************************************************
 * Copyright (c) 2013, 2014 Lectorius, Inc.
 * Authors:
 * Vijay Pandurangan (vijayp@mitro.co)
 * Evan Jones (ej@mitro.co)
 * Adam Hilss (ahilss@mitro.co)
 *
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program 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 for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *     
 *     You can contact the authors at inbound@mitro.co.
 *******************************************************************************/
package co.mitro.keyczar;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.keyczar.Crypter;
import org.keyczar.DefaultKeyType;
import org.keyczar.Encrypter;
import org.keyczar.GenericKeyczar;
import org.keyczar.KeyMetadata;
import org.keyczar.KeyVersion;
import org.keyczar.KeyczarKey;
import org.keyczar.SessionCrypter;
import org.keyczar.enums.KeyPurpose;
import org.keyczar.enums.KeyStatus;
import org.keyczar.exceptions.KeyczarException;
import org.keyczar.i18n.Messages;
import org.keyczar.interfaces.KeyczarReader;
import org.keyczar.util.Base64Coder;

import com.google.common.base.Charsets;
import com.google.common.io.Files;

public final class Util {
    private Util() {
    }

    /** Returns a GenericKeyczar containing a new generated key of type. */
    public static GenericKeyczar createKey(DefaultKeyType type, KeyPurpose purpose) throws KeyczarException {
        return createKey(type, purpose, type.defaultSize());
    }

    /** Returns a GenericKeyczar containing a new generated key of type. */
    public static GenericKeyczar createKey(DefaultKeyType type, KeyPurpose purpose, int size)
            throws KeyczarException {
        KeyMetadata metadata = new KeyMetadata("Key", purpose, type);
        KeyczarReader reader = new MemoryKeyReader(metadata, null);
        GenericKeyczar keyczar = new GenericKeyczar(reader);
        keyczar.addVersion(KeyStatus.PRIMARY, size);
        return keyczar;
    }

    /** Returns a KeyczarReader containing a new generated key of type. */
    public static KeyczarReader generateKeyczarReader(DefaultKeyType type, KeyPurpose purpose)
            throws KeyczarException {
        return generateKeyczarReader(type, purpose, type.defaultSize());
    }

    /** Returns a KeyczarReader containing a new generated key of type. */
    public static KeyczarReader generateKeyczarReader(DefaultKeyType type, KeyPurpose purpose, int size)
            throws KeyczarException {
        return readerFromKeyczar(createKey(type, purpose, size));
    }

    /** Writes input to a JSON file at path. */
    public static void writeJsonToPath(GenericKeyczar input, String path) {
        try {
            FileOutputStream output = new FileOutputStream(path);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, "UTF-8"));
            JsonWriter.write(input, writer);
            writer.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /** Reads a key from a JSON file at path. */
    public static KeyczarReader readJsonFromPath(String path) {
        return new KeyczarJsonReader(readFile(path));
    }

    public static Crypter crypterFromJson(String json) throws KeyczarException {
        KeyczarReader key = new KeyczarJsonReader(json);
        return new Crypter(key);
    }

    public static String readFile(String path) {
        try {
            return Files.toString(new File(path), Charsets.UTF_8);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Encrypts plaintext with a new session key, which is encrypted using crypter. The encrypted session
     * key and encrypted message are packed together using lenPrefixPack().
     */
    public static byte[] encryptWithSession(Encrypter crypter, byte[] plaintext) throws KeyczarException {
        // Create a session crypter
        SessionCrypter session = new SessionCrypter(crypter);
        byte[] rawEncrypted = session.encrypt(plaintext);
        byte[][] input = { session.getSessionMaterial(), rawEncrypted };
        return org.keyczar.util.Util.lenPrefixPack(input);
    }

    /**
     * Decrypts message as a session by unpacking the encrypted session key, decrypting it with crypter,
     * then decrypting the message.
     */
    public static byte[] decryptWithSession(Crypter crypter, byte[] ciphertext) throws KeyczarException {
        byte[][] unpacked = org.keyczar.util.Util.lenPrefixUnpack(ciphertext);
        SessionCrypter session = new SessionCrypter(crypter, unpacked[0]);
        return session.decrypt(unpacked[1]);
    }

    public static String encryptWithSession(Encrypter crypter, String plaintext) throws KeyczarException {
        try {
            return Base64Coder.encodeWebSafe(encryptWithSession(crypter, plaintext.getBytes("UTF-8")));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Should not happen", e);
        }
    }

    public static String decryptWithSession(Crypter crypter, String ciphertext) throws KeyczarException {
        try {
            return new String(decryptWithSession(crypter, Base64Coder.decodeWebSafe(ciphertext)), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Should not happen", e);
        }
    }

    // Hack to get access to KeyczarPrivateKey.getPublic(); see exportPublicKeys 
    static final Method getPublicMethod;
    static {
        Class<?> iface;
        try {
            iface = Util.class.getClassLoader().loadClass("org.keyczar.KeyczarPrivateKey");
            getPublicMethod = iface.getMethod("getPublic");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        getPublicMethod.setAccessible(true);
    }

    /** Returns a new Keyczar with public keys in privateKey. 
     * @throws KeyczarException */
    // This is basically copied from GenericKeyczar.publicKeyExport, which is not public.
    // TODO: Get this into GenericKeyczar upstream?
    public static KeyczarReader exportPublicKeys(GenericKeyczar privateKey) throws KeyczarException {
        KeyMetadata kmd = privateKey.getMetadata();
        // Can only export if type is *_PRIV
        KeyMetadata publicKmd = null;
        if (kmd.getType() == DefaultKeyType.DSA_PRIV) {
            if (kmd.getPurpose() == KeyPurpose.SIGN_AND_VERIFY) {
                publicKmd = new KeyMetadata(kmd.getName(), KeyPurpose.VERIFY, DefaultKeyType.DSA_PUB);
            }
        } else if (kmd.getType() == DefaultKeyType.RSA_PRIV) {
            switch (kmd.getPurpose()) {
            case DECRYPT_AND_ENCRYPT:
                publicKmd = new KeyMetadata(kmd.getName(), KeyPurpose.ENCRYPT, DefaultKeyType.RSA_PUB);
                break;
            case SIGN_AND_VERIFY:
                publicKmd = new KeyMetadata(kmd.getName(), KeyPurpose.VERIFY, DefaultKeyType.RSA_PUB);
                break;
            default:
                throw new IllegalArgumentException("Invalid key purpose: " + kmd.getPurpose());
            }
        }
        if (publicKmd == null) {
            throw new KeyczarException(
                    Messages.getString("KeyczarTool.CannotExportPubKey", kmd.getType(), kmd.getPurpose()));
        }

        HashMap<Integer, KeyczarKey> keys = new HashMap<Integer, KeyczarKey>();
        for (KeyVersion version : privateKey.getVersions()) {
            // hack to work around keyczar's accessibility limits
            try {
                KeyczarKey key = privateKey.getKey(version);
                KeyczarKey publicKey = (KeyczarKey) getPublicMethod.invoke(key);
                publicKmd.addVersion(version);
                keys.put(version.getVersionNumber(), publicKey);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }

        return new MemoryKeyReader(publicKmd, keys);
    }

    /**
     * Create a KeyczarReader from an existing key. Useful for creating a GenericKeyczar
     * to manipulate a keyset, then "re-open" the key as the correct type to use it
     * Example: Crypter crypter = new Crypter(Util.readerFromKeyczar(keyczar));
     *
     * @param keyczar
     * @return
     */
    public static KeyczarReader readerFromKeyczar(GenericKeyczar keyczar) {
        HashMap<Integer, KeyczarKey> keys = new HashMap<Integer, KeyczarKey>();
        for (KeyVersion v : keyczar.getVersions()) {
            keys.put(v.getVersionNumber(), keyczar.getKey(v));
        }
        return new MemoryKeyReader(keyczar.getMetadata(), keys);
    }

    /** Basically a copy of ImportedKeyReader which is not public. */
    private static final class MemoryKeyReader implements KeyczarReader {
        private final KeyMetadata metadata;
        private final Map<Integer, KeyczarKey> keys;

        public MemoryKeyReader(KeyMetadata metadata, Map<Integer, KeyczarKey> keys) {
            this.metadata = metadata;
            this.keys = keys;
            assert keys == null || metadata.getVersions().size() == keys.size();
        }

        @Override
        public String getKey(int version) throws KeyczarException {
            return keys.get(version).toString();
        }

        @Override
        public String getKey() throws KeyczarException {
            return keys.get(metadata.getPrimaryVersion().getVersionNumber()).toString();
        }

        @Override
        public String getMetadata() throws KeyczarException {
            return metadata.toString();
        }
    }
}