private static native boolean verify()

in src/com/amazon/corretto/crypto/provider/EvpSignature.java [105:474]


    private static native boolean verify(byte[] publicKey, long[] ctxHandle, int keyType, String digestName, int paddingType,
            String mgfMd, int saltLen, byte[] message, int offset, int length, byte[] signature, int sigOff, int sigLen);

    /**
     * Starts calculating a signature and returns a native pointer to the context.
     *
     * @param privateKey
     *            a DER PKCS8 encoded private key appropriate to the algorithm.
     * @param ctxHandle
     *            if non-zero, this is treated as a native pointer to a
     * @param keyType
     *            the integer defined by OpenSSL as the key type of the {@code privateKey}
     * @param checkPrivateKey
     *            run extra consistency checks on the private key if possible
     * @param digestName
     *            the "long name" of the digest (as defined by OpenSSL) used by the signature.
     * @param paddingType
     *            the integer defined by OpenSSL as the padding type to be used.
     * @param mgfMd
     *            the the "long name" of the digest (as defined by OpenSSL) used by the Mask
     *            Generation Function (MGF). This parameter is only necessary for RSA-PSS
     *            signatures.
     * @param saltLen
     *            the length of the salt in bytes. This parameter is only necessary for RSA-PSS
     *            signatures.
     * @param message
     *            the start of message to be signed
     * @param offset
     *            the offset in {@code message} designating the start of the data to be signed.
     * @param length
     *            the length of the data in {@code message} to be signed.
     * @return the context
     *
     * @see {@link PKCS8EncodedKeySpec}
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html">EVP_PKEY_CTX_ctrl</a>
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_base_id.html">EVP_PKEY_base_id</a>
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_get_digestbyname.html">EVP_get_digestbyname</a>
     */
    private static native long signStart(byte[] privateKey, long ctxHandle, int keyType, boolean checkPrivateKey, String digestName, int paddingType,
            String mgfMd, int saltLen, byte[] message, int offset, int length);

    /**
     * Starts calculating a signature and returns a native pointer to the context.
     *
     * @param privateKey
     *            a DER PKCS8 encoded private key appropriate to the algorithm.
     * @param ctxHandle
     *            if non-zero, this is treated as a native pointer to an @{link EvpContext}
     *            associated with the current key.
     * @param keyType
     *            the integer defined by OpenSSL as the key type of the {@code privateKey}
     * @param checkPrivateKey
     *            run extra consistency checks on the private key if possible
     * @param digestName
     *            the "long name" of the digest (as defined by OpenSSL) used by the signature.
     * @param paddingType
     *            the integer defined by OpenSSL as the padding type to be used.
     * @param mgfMd
     *            the the "long name" of the digest (as defined by OpenSSL) used by the Mask
     *            Generation Function (MGF). This parameter is only necessary for RSA-PSS
     *            signatures.
     * @param saltLen
     *            the length of the salt in bytes. This parameter is only necessary for RSA-PSS
     *            signatures.
     * @param message
     *            the start of message to be signed. Note that position and limit are ignored.
     * @return the context
     *
     * @see {@link PKCS8EncodedKeySpec}
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html">EVP_PKEY_CTX_ctrl</a>
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_base_id.html">EVP_PKEY_base_id</a>
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_get_digestbyname.html">EVP_get_digestbyname</a>
     */
    private static native long signStartBuffer(byte[] privateKey, long ctxHandle, int keyType, boolean checkPrivateKey, String digestName, int paddingType,
            String mgfMd, int saltLen, ByteBuffer message);

    /**
     * Starts verifying a signature and returns a native pointer to the context.
     *
     * @param publicKey
     *            a DER X509 encoded public key appropriate to the algorithm.
     * @param ctxHandle
     *            if non-zero, this is treated as a native pointer to an @{link EvpContext}
     *            associated with the current key.
     * @param keyType
     *            the integer defined by OpenSSL as the key type of the {@code privateKey}
     * @param digestName
     *            the "long name" of the digest (as defined by OpenSSL) used by the signature.
     * @param paddingType
     *            the integer defined by OpenSSL as the padding type to be used.
     * @param mgfMd
     *            the the "long name" of the digest (as defined by OpenSSL) used by the Mask
     *            Generation Function (MGF). This parameter is only necessary for RSA-PSS
     *            signatures.
     * @param saltLen
     *            the length of the salt in bytes. This parameter is only necessary for RSA-PSS
     *            signatures.
     * @param message
     *            the start of message to be verified
     * @param offset
     *            the offset in {@code message} designating the start of the data to be verified.
     * @param length
     *            the length of the data in {@code message} to be verified.
     * @return the context
     *
     * @see {@link X509EncodedKeySpec}
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html">EVP_PKEY_CTX_ctrl</a>
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_base_id.html">EVP_PKEY_base_id</a>
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_get_digestbyname.html">EVP_get_digestbyname</a>
     */
    private static native long verifyStart(byte[] publicKey, long ctxHandle, int keyType, String digestName, int paddingType,
            String mgfMd, int saltLen, byte[] message, int offset, int length);

    /**
     * Starts verifying a signature and returns a native pointer to the context.
     *
     * @param publicKey
     *            a DER X509 encoded public key appropriate to the algorithm.
     * @param ctxHandle
     *            if non-zero, this is treated as a native pointer to an @{link EvpContext}
     *            associated with the current key.
     * @param keyType
     *            the integer defined by OpenSSL as the key type of the {@code privateKey}
     * @param digestName
     *            the "long name" of the digest (as defined by OpenSSL) used by the signature.
     * @param paddingType
     *            the integer defined by OpenSSL as the padding type to be used.
     * @param mgfMd
     *            the the "long name" of the digest (as defined by OpenSSL) used by the Mask
     *            Generation Function (MGF). This parameter is only necessary for RSA-PSS
     *            signatures.
     * @param saltLen
     *            the length of the salt in bytes. This parameter is only necessary for RSA-PSS
     *            signatures.
     * @param message
     *            the start of message to be verified. Note that position and limit are ignored.
     * @return the context
     *
     * @see {@link X509EncodedKeySpec}
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html">EVP_PKEY_CTX_ctrl</a>
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_base_id.html">EVP_PKEY_base_id</a>
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_get_digestbyname.html">EVP_get_digestbyname</a>
     */
    private static native long verifyStartBuffer(byte[] publicKey, long ctxHandle, int keyType, String digestName, int paddingType,
            String mgfMd, int saltLen, ByteBuffer message);

    /**
     * Updates the context for signing data.
     *
     * @param ctx
     *            native context returned by either
     *            {@link #signStart(byte[], int, String, int, String, int, byte[], int, int)} or
     *            {@link #signStartBuffer(byte[], int, String, int, String, int, ByteBuffer)}
     * @param message
     *            the message to be signed
     * @param offset
     *            the offset in {@code message} designating the start of the data to be verified.
     * @param length
     *            the length of the data in {@code message} to be verified.
     */
    private static native void signUpdate(long ctx, byte[] message, int offset, int length);

    /**
     * Updates the context for signing data.
     *
     * @param ctx
     *            native context returned by either
     *            {@link #signStart(byte[], int, String, int, String, int, byte[], int, int)} or
     *            {@link #signStartBuffer(byte[], int, String, int, String, int, ByteBuffer)}
     * @param message
     *            the message to be signed. Note that position and limit are ignored.
     */
    private static native void signUpdateBuffer(long ctx, ByteBuffer message);

    /**
     * Updates the context for verifying data.
     *
     * @param ctx
     *            native context returned by either
     *            {@link #verifyStart(byte[], int, String, int, String, int, byte[], int, int)} or
     *            {@link #verifyStartBuffer(byte[], int, String, int, String, int, ByteBuffer)}
     * @param message
     *            the message to be signed
     * @param offset
     *            the offset in {@code message} designating the start of the data to be verified.
     * @param length
     *            the length of the data in {@code message} to be verified.
     */
    private static native void verifyUpdate(long ctx, byte[] message, int offset, int length);

    /**
     * Updates the context for verifying data.
     *
     * @param ctx
     *            native context returned by either
     *            {@link #verifyStart(byte[], int, String, int, String, int, byte[], int, int)} or
     *            {@link #verifyStartBuffer(byte[], int, String, int, String, int, ByteBuffer)}
     * @param message
     *            the message to be signed. Note that position and limit are ignored.
     */
    private static native void verifyUpdateBuffer(long ctx, ByteBuffer message);

    /**
     * Calculates the signature and <em>destroys the context</em>.
     *
     * @param ctx
     *            native context returned by either
     *            {@link #signStart(byte[], int, String, int, String, int, byte[], int, int)} or
     *            {@link #signStartBuffer(byte[], int, String, int, String, int, ByteBuffer)}.
     * @param preserveCtx
     *            if true indicates that the context should be preserved rather than destroyed.
     * @return the signature
     */
    private static native byte[] signFinish(long ctx, boolean preserveCtx);

    /**
     * Verifies the signature and <em>destroys the context</em>.
     *
     * @param ctx
     *            native context returned by either
     *            {@link #verifyStart(byte[], int, String, int, String, int, byte[], int, int)} or
     *            {@link #verifyStartBuffer(byte[], int, String, int, String, int, ByteBuffer)}.
     * @param signature
     *            the signature to verify
     * @param sigOff
     *            the offset in {@code signature} of the actual signature to verify
     * @param sigLen
     *            the length of the signatue to verify
     * @param preserveCtx
     *            if true indicates that the context should be preserved rather than destroyed.
     * @return true if the signature was verified. false if not.
     */
    private static native boolean verifyFinish(long ctx, byte[] signature, int sigOff, int sigLen, boolean preserveCtx);

    private final AmazonCorrettoCryptoProvider provider_;
    private final String digestName_;
    private final byte[] oneByteArray_ = new byte[1];
    private final InputBuffer<byte[], Void> signingBuffer;
    private final InputBuffer<Boolean, Void> verifyingBuffer;

    /**
     * Creates a new instances of this class.
     * @param keyType the keyType as recongized by OpenSSL for this algorithm. 
     * @param paddingType the paddingType as recognized by OpenSSL for this algorithm or {@code 0} if N/A.
     * @param digestName the long digest name as recognized by OpenSSL for this algorithm.
     * 
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html">EVP_PKEY_CTX_ctrl</a>
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_base_id.html">EVP_PKEY_base_id</a>
     * @see <a
     *      href="https://www.openssl.org/docs/man1.1.0/crypto/EVP_get_digestbyname.html">EVP_get_digestbyname</a>
     */
    private EvpSignature(AmazonCorrettoCryptoProvider provider, final EvpKeyType keyType, final int paddingType, final String digestName) {
        super(keyType, paddingType);
        Loader.checkNativeLibraryAvailability();
        provider_ = provider;
        digestName_ = digestName;

        signingBuffer = new InputBuffer<byte[], Void>(1024)
                .withInitialUpdater((src, offset, length) -> {
                        if (ctx_ == null) {
                            ctx_ = new EvpContext(signStart(keyDer_, 0, keyType_.nativeValue,
                                provider_.hasExtraCheck(ExtraCheck.PRIVATE_KEY_CONSISTENCY),
                                digestName_, paddingType_, null, 0,
                                src, offset, length));
                        } else {
                            ctx_.use(c -> signStart(keyDer_, c, keyType_.nativeValue,
                                provider_.hasExtraCheck(ExtraCheck.PRIVATE_KEY_CONSISTENCY),
                                digestName_, paddingType_, null, 0,
                                src, offset, length));
                        }
                        return null;
                })
                .withInitialUpdater((src) -> {
                    if (ctx_ == null) {
                        ctx_ = new EvpContext(signStartBuffer(keyDer_, 0, keyType_.nativeValue,
                            provider_.hasExtraCheck(ExtraCheck.PRIVATE_KEY_CONSISTENCY),
                            digestName_, paddingType_, null, 0, src));
                    } else {
                        ctx_.use(c -> signStartBuffer(keyDer_, c, keyType_.nativeValue,
                            provider_.hasExtraCheck(ExtraCheck.PRIVATE_KEY_CONSISTENCY),
                            digestName_, paddingType_, null, 0, src));
                    }
                    return null;
                })
                .withUpdater((ignored, src, offset, length) -> {
                    ctx_.useVoid(ptr -> signUpdate(ptr, src, offset, length));
                })
                .withUpdater((ignored, src) -> {
                    ctx_.useVoid(ptr -> signUpdateBuffer(ptr, src));
                })
                .withDoFinal((ignored) -> {
                        final byte[] result;
                        if (keyUsageCount_ > KEY_REUSE_THRESHOLD) {
                            result = ctx_.use(c -> signFinish(c, true));
                        } else {
                            try {
                                result = signFinish(ctx_.take(), false);
                            } finally {
                                ctx_ = null;
                            }
                        }
                        keyUsageCount_++;
                        return result;
                })
                .withSinglePass((src, offset, length) -> {
                        final byte[] result;
                        if (ctx_ != null) {
                            result = ctx_.use(c -> sign(keyDer_, new long[] {c}, keyType_.nativeValue,
                                provider_.hasExtraCheck(ExtraCheck.PRIVATE_KEY_CONSISTENCY),
                                digestName_, paddingType, null, 0,
                                  src, offset, length));
                        } else {
                          long[] handle = keyUsageCount_ > KEY_REUSE_THRESHOLD ? new long[1] : null;
                          result = sign(keyDer_, handle, keyType_.nativeValue,
                              provider_.hasExtraCheck(ExtraCheck.PRIVATE_KEY_CONSISTENCY),
                              digestName_, paddingType, null, 0,
                              src, offset, length);
                          if (handle != null) {
                            ctx_ = new EvpContext(handle[0]);
                          }
                        }
                        keyUsageCount_++;
                        return result;
                });
        verifyingBuffer = new InputBuffer<Boolean, Void>(1024)
                .withInitialUpdater((src, offset, length) -> {
                  if (ctx_ != null) {
                    ctx_.use(c -> verifyStart(keyDer_, c, keyType_.nativeValue, digestName_,
                        paddingType_, null, 0,
                        src, offset, length));
                  } else {
                    ctx_ = new EvpContext(verifyStart(keyDer_, 0, keyType_.nativeValue, digestName_,
                        paddingType_, null, 0,
                        src, offset, length));
                  }
                  return null;
                })
                .withInitialUpdater((src) -> {
                  if (ctx_ != null) {
                    ctx_.use(c -> verifyStartBuffer(keyDer_, c, keyType_.nativeValue,
                        digestName_, paddingType_, null, 0, src));
                  } else {
                    ctx_ = new EvpContext(verifyStartBuffer(keyDer_, 0, keyType_.nativeValue,
                        digestName_, paddingType_, null, 0, src));
                  }
                  return null;
                })
                .withUpdater((ignored, src, offset, length) -> {
                    ctx_.useVoid(ptr -> verifyUpdate(ptr, src, offset, length));
                })
                .withUpdater((ignored, src) -> {
                  ctx_.useVoid(ptr -> verifyUpdateBuffer(ptr, src));
                });
        // Both doFinal and SinglePass need to be defined at the very end for verify
        // because they need access to the passed in signature to verify it.
    }