com.swdouglass.joid.Crypto.java Source code

Java tutorial

Introduction

Here is the source code for com.swdouglass.joid.Crypto.java

Source

/*
 * MODIFICATIONS to the original source have been made by
 * Scott Douglass <scott@swdouglass.com>
 *
 * Copyright 2009 Scott Douglass <scott@swdouglass.com>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The original copyright notice and license terms are below.
 */

//
// (C) Copyright 2007 VeriSign, Inc.  All Rights Reserved.
//
// VeriSign, Inc. shall have no responsibility, financial or
// otherwise, for any consequences arising out of the use of
// this material. The program material is provided on an "AS IS"
// BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied.
//
// Distributed under an Apache License
// http://www.apache.org/licenses/LICENSE-2.0
//
package com.swdouglass.joid;

import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

/**
 * Implements the cryptography needed for OpenID.
 */
public class Crypto {

    /**
     * Creates an instance of the crypto library.
     */
    public Crypto() {
    }

    private DiffieHellman dh;

    /**
     * Digests a message using SHA-1.
     * @param text the bytes to digest.
     * @return the digested bytes.
     * @throws NoSuchAlgorithmException if SHA-1 is not available.
     */
    public static byte[] sha1(byte[] text) throws NoSuchAlgorithmException {
        MessageDigest d = MessageDigest.getInstance("SHA-1");
        return d.digest(text);
    }

    /**
     * Digests a message using SHA-256.
     * @param text the bytes to digest.
     * @return the digested bytes.
     * @throws NoSuchAlgorithmException if SHA-256 is not available.
     */
    public static byte[] sha256(byte[] text) throws NoSuchAlgorithmException {
        MessageDigest d = MessageDigest.getInstance("SHA-256");
        return d.digest(text);
    }

    /**
     * Signs a message using HMAC SHA1.
     *
     * @param key the key to sign with.
     * @param text the bytes to sign.
     * @return the signed bytes.
     * @throws InvalidKeyException if <code>key</code> is not a good HMAC key.
     * @throws NoSuchAlgorithmException if HMACSHA1 is not available.
     */
    public static byte[] hmacSha1(byte[] key, byte[] text) throws InvalidKeyException, NoSuchAlgorithmException {
        return hmacShaX("HMACSHA1", key, text);
    }

    /**
     * Signs a message using HMAC SHA256.
     *
     * @param key the key to sign with.
     * @param text the bytes to sign.
     * @return the signed bytes.
     * @throws InvalidKeyException if <code>key</code> is not a good HMAC key.
     * @throws NoSuchAlgorithmException if HMACSHA1 is not available.
     */
    public static byte[] hmacSha256(byte[] key, byte[] text) throws InvalidKeyException, NoSuchAlgorithmException {
        return hmacShaX("HMACSHA256", key, text);
    }

    private static byte[] hmacShaX(String keySpec, byte[] key, byte[] text)
            throws InvalidKeyException, NoSuchAlgorithmException {
        SecretKey sk = new SecretKeySpec(key, keySpec);
        Mac m = Mac.getInstance(sk.getAlgorithm());
        m.init(sk);
        return m.doFinal(text);
    }

    private static SecureRandom random;

    static {
        try {
            random = SecureRandom.getInstance("SHA1PRNG");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("No secure random available.");
        }
    }

    /**
     * Generates a random handle, in UUID format.
     *
     * @return a random handle.
     */
    public static String generateHandle() {
        return java.util.UUID.randomUUID().toString();
    }

    /**
     * Generates a random 'crumb' value.
     *
     * @return a four-byte random string.
     */
    public static String generateCrumb() {
        byte[] b = new byte[4];
        random.nextBytes(b);
        return convertToString(b);
    }

    /**
     * Generates random bytes.
     *
     * @param s the session or association type
     * @return random bytes, length fitting to the given session or
     * association type (length 0 to 32 bytes).
     */
    public byte[] generateRandom(String s) {
        int len = 0;
        if (AssociationRequest.DH_SHA1.equals(s)) {
            len = 20;
        } else if (AssociationRequest.DH_SHA256.equals(s)) {
            len = 32;
        } else if (AssociationRequest.NO_ENCRYPTION.equals(s)) {
            len = 0;
        } else if (AssociationRequest.HMAC_SHA1.equals(s)) {
            len = 20;
        } else if (AssociationRequest.HMAC_SHA256.equals(s)) {
            len = 32;
        }
        byte[] result = new byte[len];
        random.nextBytes(result);
        return result;
    }

    /**
     * Sets the Diffie-Hellman key values.
     *
     * @param mod the Diffie-Hellman modulus.
     * @param gen the Diffie-Hellman generator.
     */
    public void setDiffieHellman(BigInteger mod, BigInteger gen) {
        this.dh = new DiffieHellman(mod, gen);
    }

    /**
     * Sets the Diffie-Hellman key values.
     *
     * @param dh the Diffie-Hellman value.
     */
    public void setDiffieHellman(DiffieHellman dh) {
        this.dh = dh;
    }

    /**
     * Returns the Diffie-Hellman public key set
     * by {@link #setDiffieHellman(BigInteger, BigInteger)}.
     *
     * @return the Diffie-Hellman public key.
     * @throws IllegalArgumentException if this crypto instance has not
     * yet been initialized.
     */
    public BigInteger getPublicKey() {
        if (dh == null) {
            throw new IllegalArgumentException("DH not yet initialized");
        }
        return dh.getPublicKey();
    }

    /**
     * Decrypts a secret using Diffie-Hellman.
     *
     * @param consumerPublic the public key used to decrypt.
     * @param secret the value to decrypt.
     * @return the decrypted value.
     */
    public byte[] decryptSecret(BigInteger consumerPublic, byte[] secret) throws OpenIdException {
        return encryptSecret(consumerPublic, secret);
    }

    /**
     * Encrypts a secret using Diffie-Hellman.
     *
     * @param consumerPublic the public key used to encrypt.
     * @param secret the value to encrypt.
     * @return the encrypted secret value.
     */
    public byte[] encryptSecret(BigInteger consumerPublic, byte[] secret) throws OpenIdException {
        if (dh == null) {
            throw new IllegalArgumentException("No DH implementation set");
        }
        byte[] xoredSecret = null;
        try {
            xoredSecret = dh.xorSecret(consumerPublic, secret);
            return xoredSecret;
        } catch (NoSuchAlgorithmException e) {
            throw new OpenIdException(e);
        }
    }

    /**
     * Converts a string to bytes.
     *
     * @param s the string to convert.
     * @return the base 64 decoded bytes.
     */
    public static byte[] convertToBytes(String s) {
        return Base64.decodeBase64(s.getBytes());
    }

    /**
     * Converts bytes to string.
     *
     * @param b the bytes to encode.
     * @return the base 64 encoded string.
     */
    public static String convertToString(byte[] b) {
        String s = new String(Base64.encodeBase64(b));
        s = s.replaceAll("\n", "");
        return s;
    }

    /**
     * Converts a big integer to string.
     *
     * @param b the big integer to convert.
     * @return the base 64 encoded string.
     */
    public static String convertToString(BigInteger b) {
        return convertToString(b.toByteArray());
    }

    /**
     * Converts a base64-encoded string to big int.
     *
     * @param s the string to convert, by way of base64 decoding.
     * @return the converted big int.
     */
    public static BigInteger convertToBigIntegerFromString(String s) {
        return new BigInteger(Base64.decodeBase64(s.getBytes()));
    }
}