private void noPrefixVerify(final byte[] signature, final byte[] data)
      throws GeneralSecurityException {
    // The algorithm is described at (https://tools.ietf.org/html/rfc8017#section-8.2). As signature
    // verification is a public operation,  throwing different exception messages doesn't give
    // attacker any useful information.
    BigInteger e = publicKey.getPublicExponent();
    BigInteger n = publicKey.getModulus();
    int nLengthInBytes = (n.bitLength() + 7) / 8;

    // Step 1. Length checking.
    if (nLengthInBytes != signature.length) {
      throw new GeneralSecurityException("invalid signature's length");
    }

    // Step 2. RSA verification.
    BigInteger s = SubtleUtil.bytes2Integer(signature);
    if (s.compareTo(n) >= 0) {
      throw new GeneralSecurityException("signature out of range");
    }
    BigInteger m = s.modPow(e, n);
    byte[] em = SubtleUtil.integer2Bytes(m, nLengthInBytes);

    // Step 3. PKCS1 encoding.
    byte[] expectedEm = emsaPkcs1(data, nLengthInBytes, hash);

    // Step 4. Compare the results.
    if (!Bytes.equal(em, expectedEm)) {
      throw new GeneralSecurityException("invalid signature");
    }
  }
RsaSsaPkcs1 (i.e. RSA Signature Schemes with Appendix (SSA) using PKCS1-v1_5 encoding) verifying
with JCE.
java_src/src/main/java/com/google/crypto/tink/subtle/RsaSsaPkcs1VerifyJce.java