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