I'm a total newbie when it comes to cryptography and such things. I don't (and dont want to) know the details of the SHA256 and RSA. I "know" what they do, not how they do it, and for now that's enough.
I'm wondering what the "SHA256withRSA"-algorithm (if you can call it that) actually do and in what order. For example, does it hash the data with SHA256 and then encrypts it using RSA or is it vice-versa, or something else?
The reason I'm asking is because I wanna do the java equivalent of:
Signature.getInstance("SHA256withRSA")
signature.initSign(privateKey); //privateKey == a key extracted from a .p12 file
in Objective-C on iOS. And I couldn't seem to find any stuff that does exactly this, therefore I'm asking, can I just hash the data (SHA256) and then encrypt it (RSA) (or vice-versa) and get the same behavior?
What is the suggested solution for doing this kind of thing?
Thank you!
EDIT: I failed to mention that I sign the data using a private key that is obtained by doing:
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(new FileInputStream(new File(filename)), password.toCharArray());
PrivateKey privateKey = (PrivateKey)keystore.getKey(alias, password.toCharArray());
Where filename is for example: "/somewhere/mykey.p12".
"SHA256withRSA"
implements the PKCS#1 v1.5 padding and modular exponentiation with the formal name RSASSA-PKCS1-v1_5 after calculating the hash over the data using SHA256.
The general strategy for signature generation is:
The strategy for signature verification consists of two parts.
Part 1:
The result of part 1 is the locally generated padded hash (called EM').
Part 2:
The result of part 2 is the original padded hash (called EM).
Finally the original and local padded hashes (EM and EM') are compared; the signature verifies if the comparison succeeds.
The PSS scheme in PKCS#1 v2.0 onward has been designed to provide a non-deterministic scheme with a better security proof for the padding. For new protocols it is advisable to use the PSS scheme instead, although the PKCS#1 v1.5 scheme is still considered secure.
The modular exponentiation during signature generation may not use the private exponent; it quite often uses the Chinese Remainder Theorem if the CRT parameters are present for a ~4x speedup.
OS2IP converts an octet string (or byte array) to an integer by interpreting it as a statically sized unsigned big endian value, I2OSP performs the reverse operation. If the runtime can directly perform big integer calculations on the binary representation then the conversion is implicit (i.e. doesn't need to be performed at all).
The PKCS#1 v1.5 padding used for encryption and signature generation is different, so using encryption may result in erroneous signatures.
An alternative verification method is to extract the hash from the padding and perform a compare of the hash values.
With regards to the padding in iOS, please check this answer by Thomas Pornin. Basically you should create the SHA-256 hash, prefix a static block of data (defined in the PKCS#1 specifications) then use SecKeyRawSign
using kSecPaddingPKCS1
.
For your convenience, the PKCS#1 defined block of data that needs to be prefixed for SHA-256 is displayed below in hexadecimals. It can be somewhat hard to find in the RFC, it's in the notes of section 9.2:
30 31 30 0D 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20