/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.jss.pkcs11;

import org.mozilla.jss.crypto.CryptoToken;
import org.mozilla.jss.crypto.SymmetricKey;

// We've updated jss.crypto.SymmetricKey to extend javax.crypto.SecretKey, so
// PK11SymKey implements that interface as well.
public final class PK11SymKey implements SymmetricKey {

    protected PK11SymKey(byte[] pointer) {
        assert(pointer!=null);
        keyProxy  = new SymKeyProxy(pointer);
        nickName = null;
    }

    protected PK11SymKey(byte[] pointer,String nickName) {
        assert(pointer!=null);
        keyProxy  = new SymKeyProxy(pointer);
        this.nickName = nickName;
     }

    private SymKeyProxy keyProxy;
    private String nickName;

    @Override
    public SymmetricKey.Type getType() {
        KeyType kt = getKeyType();

        SymmetricKey.Type result = SymmetricKey.Type.fromKeyType(kt);
        if (result == null) {
            throw new RuntimeException("Unrecognized key type: " + kt);
        }

        return result;
    }

    @Override
    public native CryptoToken getOwningToken();

    /**
     * Returns key strength, measured as the number of bits of secret material.
     * <b>NOTE:</b> Due to a bug in the security library (333440), this
     *  may return a wrong answer for PBE keys that have embedded parity
     *  (like DES).  A DES key is 56 bits of information plus
     *  8 bits of parity, so it takes up 64 bits.  For a normal DES key,
     * this method will correctly return 56, but for a PBE-generated DES key,
     * the security library bug causes it to return 64.
     */
    @Override
    public native int getStrength();


    /**
     * Returns the length of the key in bytes, as returned by
     * PK11_GetKeyLength().
     */
    @Override
    public native int getLength();

    @Override
    public native byte[] getKeyData()
        throws SymmetricKey.NotExtractableException;

    public native KeyType getKeyType();

    @Override
    public String getAlgorithm() {
        return getKeyType().toString();
    }

    @Override
    public byte[] getEncoded() {
        try {
            return getKeyData();
        } catch(SymmetricKey.NotExtractableException nee) {
            return null;
        }
    }

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

    @Override
    public String getNickName() {
        return nickName;
    }

    @Override
    public void setNickName(String nickName) {
        this.nickName = nickName;

        if( nickName != null) {
            setNickNameNative(nickName);
        }
    }

    public native void setNickNameNative(String nickName);
}

class SymKeyProxy extends KeyProxy {

    public SymKeyProxy(byte[] pointer) {
        super(pointer);
    }

    @Override
    protected native void releaseNativeResources();

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
    }
}
