All checks were successful
DCO / DCO (pull_request) Successful in 28s
Signed-off-by: Ori Bruk <o.bruk@yadro.com>
121 lines
5.2 KiB
Java
121 lines
5.2 KiB
Java
package info.frostfs.sdk.tools;
|
|
|
|
import com.google.protobuf.ByteString;
|
|
import com.google.protobuf.Message;
|
|
import frostfs.session.Types;
|
|
import info.frostfs.sdk.constants.CryptoConst;
|
|
import info.frostfs.sdk.jdo.ECDsa;
|
|
import org.apache.commons.codec.digest.DigestUtils;
|
|
import org.bouncycastle.asn1.sec.SECNamedCurves;
|
|
import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
|
|
import org.bouncycastle.crypto.params.ECDomainParameters;
|
|
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
|
import org.bouncycastle.crypto.signers.ECDSASigner;
|
|
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
|
|
|
|
import java.math.BigInteger;
|
|
import java.security.Signature;
|
|
|
|
import static info.frostfs.sdk.constants.FieldConst.*;
|
|
import static org.bouncycastle.crypto.util.DigestFactory.createSHA256;
|
|
import static org.bouncycastle.util.BigIntegers.asUnsignedByteArray;
|
|
|
|
public class RequestSigner {
|
|
public static final String ERROR_UNSUPPORTED_TYPE_TEMPLATE = "Unsupported message type: %s";
|
|
public static final int RFC6979_SIGNATURE_SIZE = 64;
|
|
|
|
private RequestSigner() {
|
|
}
|
|
|
|
public static byte[] signData(ECDsa key, byte[] data) {
|
|
var hash = new byte[65];
|
|
hash[0] = 0x04;
|
|
try {
|
|
Signature signature = Signature.getInstance(CryptoConst.SIGNATURE_ALGORITHM);
|
|
signature.initSign(key.getPrivateKey());
|
|
signature.update(DigestUtils.sha512(data));
|
|
byte[] sig = signature.sign();
|
|
System.arraycopy(sig, 0, hash, 1, sig.length);
|
|
} catch (Exception exp) {
|
|
throw new RuntimeException(exp);
|
|
}
|
|
|
|
return hash;
|
|
}
|
|
|
|
public static byte[] signRFC6979(ECDsa key, byte[] data) {
|
|
var digest = createSHA256();
|
|
var secp256R1 = SECNamedCurves.getByOID(SECObjectIdentifiers.secp256r1);
|
|
|
|
var ecParameters = new ECDomainParameters(secp256R1.getCurve(), secp256R1.getG(), secp256R1.getN());
|
|
var ecPrivateKey = new ECPrivateKeyParameters(new BigInteger(1, key.getPrivateKeyByte()), ecParameters);
|
|
var signer = new ECDSASigner(new HMacDSAKCalculator(digest));
|
|
var hash = new byte[digest.getDigestSize()];
|
|
|
|
digest.update(data, 0, data.length);
|
|
digest.doFinal(hash, 0);
|
|
signer.init(true, ecPrivateKey);
|
|
|
|
var rs = signer.generateSignature(hash);
|
|
var rBytes = asUnsignedByteArray(rs[0]);
|
|
var sBytes = asUnsignedByteArray(rs[1]);
|
|
|
|
var signature = new byte[RFC6979_SIGNATURE_SIZE];
|
|
var index = RFC6979_SIGNATURE_SIZE / 2 - rBytes.length;
|
|
System.arraycopy(rBytes, 0, signature, index, rBytes.length);
|
|
index = RFC6979_SIGNATURE_SIZE - sBytes.length;
|
|
System.arraycopy(sBytes, 0, signature, index, sBytes.length);
|
|
return signature;
|
|
}
|
|
|
|
public static frostfs.refs.Types.SignatureRFC6979 signRFC6979(ECDsa key, Message message) {
|
|
return frostfs.refs.Types.SignatureRFC6979.newBuilder()
|
|
.setKey(ByteString.copyFrom(key.getPublicKeyByte()))
|
|
.setSign(ByteString.copyFrom(signRFC6979(key, message.toByteArray())))
|
|
.build();
|
|
}
|
|
|
|
public static frostfs.refs.Types.SignatureRFC6979 signRFC6979(ECDsa key, ByteString data) {
|
|
return frostfs.refs.Types.SignatureRFC6979.newBuilder()
|
|
.setKey(ByteString.copyFrom(key.getPublicKeyByte()))
|
|
.setSign(ByteString.copyFrom(signRFC6979(key, data.toByteArray())))
|
|
.build();
|
|
}
|
|
|
|
public static frostfs.refs.Types.Signature signMessagePart(ECDsa key, Message data) {
|
|
var data2Sign = data.getSerializedSize() == 0 ? new byte[]{} : data.toByteArray();
|
|
return frostfs.refs.Types.Signature.newBuilder()
|
|
.setKey(ByteString.copyFrom(key.getPublicKeyByte()))
|
|
.setSign(ByteString.copyFrom(signData(key, data2Sign)))
|
|
.build();
|
|
}
|
|
|
|
public static void sign(Message.Builder request, ECDsa key) {
|
|
var meta = MessageHelper.getField(request, META_HEADER_FIELD_NAME);
|
|
var body = MessageHelper.getField(request, BODY_FIELD_NAME);
|
|
var verify = MessageHelper.getField(request, VERIFY_HEADER_FIELD_NAME);
|
|
var verifyOrigin = MessageHelper.getField(verify, ORIGIN_FIELD_NAME);
|
|
|
|
Message.Builder verifyBuilder;
|
|
if (verify instanceof Types.RequestVerificationHeader) {
|
|
verifyBuilder = Types.RequestVerificationHeader.newBuilder();
|
|
} else if (verify instanceof Types.ResponseVerificationHeader) {
|
|
verifyBuilder = Types.ResponseVerificationHeader.newBuilder();
|
|
} else {
|
|
throw new IllegalArgumentException(
|
|
String.format(ERROR_UNSUPPORTED_TYPE_TEMPLATE, verify.getClass().getName())
|
|
);
|
|
}
|
|
|
|
if (verifyOrigin.getSerializedSize() == 0) {
|
|
MessageHelper.setField(verifyBuilder, BODY_SIGNATURE_FIELD_NAME, signMessagePart(key, body));
|
|
} else {
|
|
MessageHelper.setField(verifyBuilder, ORIGIN_FIELD_NAME, verifyOrigin);
|
|
}
|
|
|
|
MessageHelper.setField(verifyBuilder, META_SIGNATURE_FIELD_NAME, signMessagePart(key, meta));
|
|
MessageHelper.setField(verifyBuilder, ORIGIN_SIGNATURE_FIELD_NAME, signMessagePart(key, verifyOrigin));
|
|
MessageHelper.setField(request, VERIFY_HEADER_FIELD_NAME, verifyBuilder.build());
|
|
}
|
|
|
|
}
|