frostfs-sdk-java/cryptography/src/main/java/info/frostfs/sdk/KeyExtension.java
Ori Bruk db74919401
All checks were successful
DCO / DCO (pull_request) Successful in 27s
Verify code phase / Verify code (pull_request) Successful in 1m38s
[#45] Add the ability to create a client via wallet and password
Signed-off-by: Ori Bruk <o.bruk@yadro.com>
2025-03-05 11:14:42 +03:00

93 lines
4 KiB
Java

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);
}
}
}