package info.frostfs.sdk; import info.frostfs.sdk.exceptions.ProcessFrostFSException; import info.frostfs.sdk.exceptions.ValidationFrostFSException; import org.bouncycastle.asn1.sec.SECNamedCurves; import org.bouncycastle.asn1.sec.SECObjectIdentifiers; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.jce.spec.ECNamedCurveSpec; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.ECParameterSpec; import java.security.spec.ECPrivateKeySpec; import java.security.spec.ECPublicKeySpec; import java.security.spec.InvalidKeySpecException; import static info.frostfs.sdk.constants.ErrorConst.COMPRESSED_PUBLIC_KEY_WRONG_LENGTH_TEMPLATE; import static info.frostfs.sdk.constants.ErrorConst.INPUT_PARAM_IS_MISSING; import static java.util.Objects.isNull; import static org.bouncycastle.util.BigIntegers.fromUnsignedByteArray; public class KeyExtension { private static final String CURVE_NAME = "secp256r1"; private static final String SECURITY_ALGORITHM = "EC"; private static final int COMPRESSED_PUBLIC_KEY_LENGTH = 33; private KeyExtension() { } public static PrivateKey loadPrivateKey(byte[] privateKey) { checkInputValue(privateKey); X9ECParameters params = SECNamedCurves.getByOID(SECObjectIdentifiers.secp256r1); ECDomainParameters domain = new ECDomainParameters( params.getCurve(), params.getG(), params.getN(), params.getH() ); ECPrivateKeyParameters ecParams = new ECPrivateKeyParameters(fromUnsignedByteArray(privateKey), domain); ECParameterSpec ecParameterSpec = new ECNamedCurveSpec( CURVE_NAME, params.getCurve(), params.getG(), params.getN(), params.getH() ); ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(ecParams.getD(), ecParameterSpec); try { KeyFactory kf = KeyFactory.getInstance(SECURITY_ALGORITHM); return kf.generatePrivate(privateKeySpec); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { throw new ProcessFrostFSException(e); } } public static PublicKey getPublicKeyFromBytes(byte[] publicKey) { checkInputValue(publicKey); if (publicKey.length != COMPRESSED_PUBLIC_KEY_LENGTH) { throw new ValidationFrostFSException(String.format( COMPRESSED_PUBLIC_KEY_WRONG_LENGTH_TEMPLATE, COMPRESSED_PUBLIC_KEY_LENGTH, publicKey.length )); } X9ECParameters secp256R1 = SECNamedCurves.getByOID(SECObjectIdentifiers.secp256r1); ECDomainParameters domain = new ECDomainParameters( secp256R1.getCurve(), secp256R1.getG(), secp256R1.getN(), secp256R1.getH() ); var ecPoint = secp256R1.getCurve().decodePoint(publicKey); var publicParams = new ECPublicKeyParameters(ecPoint, domain); java.security.spec.ECPoint point = new java.security.spec.ECPoint( publicParams.getQ().getRawXCoord().toBigInteger(), publicParams.getQ().getRawYCoord().toBigInteger() ); ECParameterSpec ecParameterSpec = new ECNamedCurveSpec( CURVE_NAME, secp256R1.getCurve(), secp256R1.getG(), secp256R1.getN(), secp256R1.getH(), secp256R1.getSeed() ); ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(point, ecParameterSpec); try { KeyFactory kf = KeyFactory.getInstance(SECURITY_ALGORITHM); return kf.generatePublic(publicKeySpec); } catch (Exception e) { throw new ProcessFrostFSException(e); } } private static void checkInputValue(byte[] data) { if (isNull(data) || data.length == 0) { throw new ValidationFrostFSException(INPUT_PARAM_IS_MISSING); } } }