/*
 * blanco Framework
 * Copyright (C) 2004-2007 IGA Tosiki
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */
package blanco.encryption;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;

/**
 * 秘密鍵を扱うためのユーティリティクラス。
 * 
 * @author IGA Tosiki
 */
public class BlancoEncryptionSecretKeyUtil {
    /**
     * トリプルDES用のSHA-256ダイジェストを活用した秘密鍵を作成します。
     * 
     * SHA-256は32バイトあるので、DESedeで必要となる24バイトより長いので DESedeで利用する際にはちょうど都合が良いのです。
     * 
     * @param argPassword
     *            パスワード文字列。秘密鍵の種として利用される文字列。
     * @return 生成された秘密鍵。
     */
    public static SecretKey getSha256KeyForDesede(final String argPassword) {
        final String encryptAlgorithm = "DESede";
        final String keyDigestAlgorithm = "SHA-256";

        final byte[] digestedKey = getMessageDigest(keyDigestAlgorithm,
                argPassword);

        // 実際に利用するキーを作成します。
        // 最初の24バイトのみ利用します。
        final byte[] keySeed = copyBytes(digestedKey, 24);

        try {
            final SecretKeyFactory factory = SecretKeyFactory
                    .getInstance(encryptAlgorithm);

            // DESede用のキーを取得。
            return factory.generateSecret(new DESedeKeySpec(keySeed));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("アルゴリズムの取得に失敗しました。:"
                    + e.toString());
        } catch (InvalidKeyException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("秘密鍵が不正です。:" + e.toString());
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("秘密鍵の仕様が不正です。:" + e.toString());
        }
    }

    /**
     * 指定のメッセージダイジェストアルゴリズムを利用してメッセージダイジェスト値を取得します。
     * 
     * @param argDigestAlgorithm
     *            ダイジェスト・アルゴリズム。
     * @param argInputString
     *            元となる文字列。
     * @return メッセージダイジェスト値。
     */
    public static byte[] getMessageDigest(final String argDigestAlgorithm,
            final String argInputString) {
        try {
            final MessageDigest msgDigest = MessageDigest
                    .getInstance(argDigestAlgorithm);
            msgDigest.update(argInputString.getBytes("UTF-8"));
            return msgDigest.digest();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("ダイジェスト[" + argDigestAlgorithm
                    + "]取得に失敗しました。:" + e.toString());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("ダイジェストの際に文字エンコーディングに関する例外発生:"
                    + e.toString());
        }
    }

    /**
     * 与えられたバイト配列を元に、指定の長さのバイト配列を取得します。
     * 
     * @param argInput
     * @param argLength
     * @return
     */
    private static byte[] copyBytes(final byte[] argInput, final int argLength) {
        final byte[] keySeed = new byte[argLength];
        for (int index = 0; index < keySeed.length; index++) {
            keySeed[index] = argInput[index];
        }
        return keySeed;
    }
}
