/*
* Copyright 2011 Licel LLC.
*
* 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.
*/
package com.licel.jcardsim.crypto;
import java.math.BigInteger;
import java.security.SecureRandom;
import javacard.framework.JCSystem;
import javacard.security.CryptoException;
import javacard.security.ECKey;
import javacard.security.KeyBuilder;
import javacard.security.KeyPair;
import org.bouncycastle.asn1.sec.SECNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
/**
* Base class for
* <code>ECPublicKeyImpl/ECPrivateKeyImpl</code> on BouncyCastle CryptoAPI.
*
* @see ECKey
*/
public abstract class ECKeyImpl extends KeyImpl implements ECKey {
protected ByteContainer a = new ByteContainer();
protected ByteContainer b = new ByteContainer();
protected ByteContainer g = new ByteContainer();
protected ByteContainer r = new ByteContainer();
protected ByteContainer fp = new ByteContainer();
protected short k;
protected short e1;
protected short e2;
protected short e3;
protected boolean isKInitialized;
/**
* Construct not-initialized ecc key
*
* @param keyType - key type
* @param keySize - key size in bits
* @see KeyPair
* @see KeyBuilder
*/
public ECKeyImpl(byte keyType, short keySize) {
this.size = keySize;
this.type = keyType;
setDomainParameters(getDefaultsDomainParameters(type, size));
}
/**
* Construct and initialize ecc key with ECKeyParameters. Use in KeyPairImpl
*
* @see KeyPair
* @see ECKeyParameters
* @param parameters key params from BouncyCastle API
*/
public ECKeyImpl(ECKeyParameters parameters) {
boolean isPrivate = parameters.isPrivate();
boolean isF2M = parameters.getParameters().getCurve() instanceof ECCurve.F2m;
type = isPrivate ? (isF2M ? KeyBuilder.TYPE_EC_F2M_PRIVATE : KeyBuilder.TYPE_EC_FP_PRIVATE)
: (isF2M ? KeyBuilder.TYPE_EC_F2M_PUBLIC : KeyBuilder.TYPE_EC_FP_PUBLIC);
size = (short) parameters.getParameters().getCurve().getFieldSize();
setDomainParameters(parameters.getParameters());
}
public void clearKey() {
a.clear();
b.clear();
g.clear();
r.clear();
fp.clear();
k = 0;
e1 = 0;
e2 = 0;
e3 = 0;
}
protected boolean isDomainParametersInitialized() {
return (a.isInitialized() && b.isInitialized() && g.isInitialized() && r.isInitialized()
&& isKInitialized && (fp.isInitialized() || k != 0));
}
public void setFieldFP(byte[] buffer, short offset, short length) throws CryptoException {
fp.setBytes(buffer, offset, length);
}
public void setFieldF2M(short e) throws CryptoException {
setFieldF2M(e, (short) 0, (short) 0);
}
public void setFieldF2M(short e1, short e2, short e3) throws CryptoException {
this.e1 = e1;
this.e2 = e2;
this.e3 = e3;
}
public void setA(byte[] buffer, short offset, short length) throws CryptoException {
a.setBytes(buffer, offset, length);
}
public void setB(byte[] buffer, short offset, short length) throws CryptoException {
b.setBytes(buffer, offset, length);
}
public void setG(byte[] buffer, short offset, short length) throws CryptoException {
g.setBytes(buffer, offset, length);
}
public void setR(byte[] buffer, short offset, short length) throws CryptoException {
r.setBytes(buffer, offset, length);
}
public void setK(short K) {
this.k = K;
isKInitialized = true;
}
public short getField(byte[] buffer, short offset) throws CryptoException {
return fp.getBytes(buffer, offset);
}
public short getA(byte[] buffer, short offset) throws CryptoException {
return a.getBytes(buffer, offset);
}
public short getB(byte[] buffer, short offset) throws CryptoException {
return b.getBytes(buffer, offset);
}
public short getG(byte[] buffer, short offset) throws CryptoException {
return g.getBytes(buffer, offset);
}
public short getR(byte[] buffer, short offset) throws CryptoException {
return r.getBytes(buffer, offset);
}
public short getK() throws CryptoException {
if (!isKInitialized) {
CryptoException.throwIt(CryptoException.UNINITIALIZED_KEY);
}
return k;
}
/**
* Get
* <code>ECDomainParameters</code>
*
* @return parameters for use with BouncyCastle API
* @see ECDomainParameters
*/
public ECDomainParameters getDomainParameters() {
if (!isDomainParametersInitialized()) {
CryptoException.throwIt(CryptoException.UNINITIALIZED_KEY);
}
ECCurve curve = null;
if (fp.isInitialized()) {
curve = new ECCurve.Fp(fp.getBigInteger(), a.getBigInteger(), b.getBigInteger());
} else {
curve = new ECCurve.F2m(size, e1, e2, e3, a.getBigInteger(), b.getBigInteger(),
r.getBigInteger(), BigInteger.valueOf(k));
}
return new ECDomainParameters(curve, curve.decodePoint(g.getBytes(JCSystem.CLEAR_ON_RESET)),
r.getBigInteger(), BigInteger.valueOf(k));
}
/**
* Set
* <code>ECDomainParameters</code> for EC curve
*
* @param parameters
* @see ECDomainParameters
*/
final void setDomainParameters(ECDomainParameters parameters) {
a.setBigInteger(parameters.getCurve().getA().toBigInteger());
b.setBigInteger(parameters.getCurve().getB().toBigInteger());
// generator
g.setBytes(parameters.getG().getEncoded());
// order
r.setBigInteger(parameters.getN());
// cofactor
setK(parameters.getH().shortValue());
if (parameters.getCurve() instanceof ECCurve.Fp) {
ECCurve.Fp ecfp = (ECCurve.Fp) parameters.getCurve();
fp.setBigInteger(ecfp.getQ());
} else {
ECCurve.F2m ecf2m = (ECCurve.F2m) parameters.getCurve();
setFieldF2M((short) ecf2m.getK1(), (short) ecf2m.getK2(), (short) ecf2m.getK3());
}
}
/**
* Get
* <code>ECKeyGenerationParameters</code>
*
* @param rnd Secure Random Generator
* @return parameters for use with BouncyCastle API
*/
public KeyGenerationParameters getKeyGenerationParameters(SecureRandom rnd) {
if (isDomainParametersInitialized()) {
return new ECKeyGenerationParameters(getDomainParameters(), rnd);
}
return new ECKeyGenerationParameters(getDefaultsDomainParameters(type, size), rnd);
}
/**
* Get default
* <code>ECKeyGenerationParameters</code>
*
* @param algorithm
* @param keySize key size in bits
* @param rnd Secure Random Generator
* @return parameters for use with BouncyCastle API
*/
static KeyGenerationParameters getDefaultKeyGenerationParameters(byte algorithm, short keySize, SecureRandom rnd) {
byte keyType = algorithm == KeyPair.ALG_EC_FP ? KeyBuilder.TYPE_EC_FP_PUBLIC : KeyBuilder.TYPE_EC_F2M_PUBLIC;
return new ECKeyGenerationParameters(getDefaultsDomainParameters(keyType, keySize), rnd);
}
/**
* Get defaults
* <code>ECDomainParameters</code> for EC curve
* {@link http://www.secg.org/collateral/sec2_final.pdf}
*
* @param keyType
* @param keySize
* @return parameters for use with BouncyCastle API
* @see ECDomainParameters
*/
static ECDomainParameters getDefaultsDomainParameters(byte keyType, short keySize) {
String curveName = "";
switch (keySize) {
case 113:
case 131:
case 163:
case 193:
case 233:
case 283:
case 408:
case 571:
if ((keyType != KeyBuilder.TYPE_EC_F2M_PRIVATE) & (keyType != KeyBuilder.TYPE_EC_F2M_PUBLIC)) {
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
}
curveName = "sect" + keySize + "r1";
break;
case 112:
case 128:
case 160:
case 192:
case 224:
case 256:
case 384:
case 521:
if ((keyType != KeyBuilder.TYPE_EC_FP_PRIVATE) & (keyType != KeyBuilder.TYPE_EC_FP_PUBLIC)) {
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
}
curveName = "secp" + keySize + "r1";
break;
default:
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
break;
}
X9ECParameters x9params = SECNamedCurves.getByName(curveName);
return new ECDomainParameters(
x9params.getCurve(),
x9params.getG(), // G
x9params.getN(), x9params.getH(), x9params.getSeed());
}
public void copyDomainParametersFrom(ECKey eckey) throws CryptoException {
throw new UnsupportedOperationException("Not supported yet.");
}
}