SHA256withRSA what does it do and in what order? - java

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.
So the general order is:
hashing;
padding the hash for signature generation;
modular exponentiation using the private exponent and the modulus.
The padding used for encryption and signature generation is different, so using encryption may result in erroneous signatures.
The PKCS#1 v1.5 padding scheme has been superseded by PSS. For new protocols it is advisable to use the PSS scheme instead. For RSA a very readable public standard exists. This standard has also been used as a base for RFC 3447: Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.1 (which is basically a copy).
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 in hex notation for SHA-256 (it can be bit hard to find in the standard documents, 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
Notes:
The above steps do not include the conversion from bytes to integer and vice versa. The result of raw RSA operations are generally converted to an unsigned big endian encoding with the same size of the modulus in bytes (which is generally the same as the key size, as the key size is already a multiple of 8). These conversions are called I2OSP and OS2IP in the RFC's.

Related

How to calculate RSA MD5 signature in separate steps?

I use the following 2 steps to calculate the signature, why is it different
Use java code
1- Signature s1 = Signature.getInstance("MD5withRSA");
// some code
String b1 = base64Encode(doFinalData);
2- byte[] md5 = MD5.md5("data content");
byte[] rsa = RSA.rsa(md5);
String b2 = base64Encode(rsa);
// Why b1 and b2 are not equal
Is my understanding wrong, or the code is wrong
I'm not sure which library you are using for #2, but it looks like raw RSA encryption.
When you perform "MD5withRSA" in #1 you'll actually use PKCS#1 v1.5 padding for signature generation. This will create a structure that specifies the MD5 algorithm and the MD5 signature value. Then it will pad that, and finally it will perform the modular exponentiation with the private key. The steps are described in detail in the standard.
However, if #2 is just raw RSA then it will simply convert the MD5 to a positive integer and use that as input for modular exponentiation. So the padding and structure before the MD5 hash is missing.
Just a small additional note: the signature scheme using PKCS#1 v1.5 and raw RSA are deterministic. This is not a property that is present for all schemes: RSA-PSS or ECDSA will always generate different signature values. So to test if a signature is valid, you'll have to perform the signature verification using the public key rather than a binary compare.

Why keys generated from a Java DES KeyGenerator have incorrect size?

I'm using Java's SunJCE provider to generate a 7 bit key:
KeyGenerator v = KeyGenerator.getInstance("DES")
Provider p = v.getProvider
assert(p.getClass().getSimpleName() == "SunJCE")
v.init(56)
Key k = v.generateKey()
assert(k.getEncoded().getLength == 7)
When I run the above program, I got the error that indicated that the length of k is actually 8 (64 bit) instead of 56 bit, the strange thing is that the KeyGenerator is initialized to generate only 56 bit key, so why the actual length of k is incorrect?
DES keys are encoded using 8 bits for each 7 bits, where the least significant bit of each byte is used to make the number of bits odd. So if the first 7 bits have 6, 4 or 2 bits set to one then the least significant one is set (to one). It is reset / unset / left at zero otherwise. So a 56 bit DES key is encoded as 64 bits / 8 bytes, a 112 bit 2 key used for triple DES is encoded as 128 bits and 168 bits DES keys are encoded using 192 bits.
The parity bits can be used as some kind of check to see if the DES key hasn't been altered (although it isn't very good for that either). Most DES implementations will nowadays simply ignore the parity bits altogether, but the Java KeyGenerator will still correctly set them. You can test this by validating Integer.bitCount(b & 0xFF) % 2 == 1 for each byte b in the resulting key: it should always return true.
More modern symmetric ciphers try to use fully (pseudo-)random keys; 256 bit AES or HMAC keys consist simply of randomized bytes.
This isn't true for most asymmetric ciphers; encoding the public or private key of most asymmetric ciphers will result in significantly more bits than the key size. The key size for asymmetric ciphers is usually the size of the parameter that determines the strength of the key, e.g. the size of the modulus for RSA.
Notes:
DES only has a key size (and strength) of 56 bits, and is considered completely broken: use a key of 128 bits or more (which also rules out two-key 112 bit triple DES keys, if you were paying attention) and a modern cipher such as AES.
Your assertions test things that should always be true and make little sense to me. If anything should be tested it is the random number generator that is used to generate the keys (and those are notoriously hard to test, unfortunately).
When testing for the provider name - a dangerous and non-portable practice if you ask me - then you should at least use Provider#getName() (and possibly the other getters that return useful info about the provider) rather than the class name. The class name is an implementation detail and could actually change - even if the provider name doesn't.

How does PHP handle 32 byte keys for tripledes encryption

Apologies all - newbie at encryption - been googling for days and finally asking outright.
I need to use PHP to encrypt and decrypt data that is readable by a Java TripleDES "DESede/ECB/NoPadding" function.
In Java there is a double-length 32 character key e.g. "F4D5CBDF57FEEDCFA41FD6AFE7BCDFEA" which gets converted to bytes and which provides an encrypted result without any problems. (I don't have the code.)
In PHP, when the same key is attempted via mcrypt for a tripledes, ecb function call, there is a key-length error because the system expects a max of 24 characters.
What do I need to do to the key so that PHP will produce the same encrypted result as Java?
As NullUserException postulated: please convert the key from hexadecimals to binary before using it for your triple DES cipher. Your Java code must do the same thing; in Java a triple DES key must have either 24 bytes or 16 bytes (16 bytes is only supported for later versions of Java, previously you had to convert to 24 bytes by copying the first 8 bytes to the end to create an "ABA" DES key).
32 byte keys are never supported for triple DES. If you are using the horrible mcrypt libraries for PHP however, the key gets cut to the highest key size available. So instead of a fail-fast situation, PHP rather would have their users pull their hair out in frustration.

Will Java Bouncy Castle Always Throw Exception when decrypt Plain text

I have a process in my system that will receive input either random plain texts or a ciphertexts. Since performance is not an issue, i'm planning to try decrypt all incoming input, with pseudo-code something like this:
//get the input, either a plain text, or cipher text 'in disguise'
//ex of plain text: "some text".getBytes()
byte[] plainText = getInput();
try {
//try to decrypt whatever it is. Using Bouncy Castle as the AES crypto engine
plainText = AESDecryptor.decrypt(HARDCODED_AES_KEY, plainText);
} catch(Exception ex) {
...
}
//do some process with the plain text
process(plainText);
I'm using AES for the encryption method.
The code above rely heavily on an assumption that trying to decrypt a plain text using bouncy castle will always throws exception. But is the assumption 100% correct? will it always throws exception when trying to decrypt plain, human readable text?
Thanks in advance!
Short answer
No, you cannot guarantee an exception.
Longer answer
The probability of receiving an exception is dependent upon the padding scheme used. When a cryptographic library decrypts data using an algorithm that includes padding, it expects to find correctly padded plaintext. If the padding is malformed (e.g. because the input was plaintext, not ciphertext) an exception is likely to be thrown.
If you are not using a padding scheme in your decryption and your input is a multiple of the block size of the cipher (in the case of AES - 16 bytes), then your library will happily decrypt plaintext and give you junk.
As an example, consider PKCS #7 padding. This appends a non-zero number of bytes to the end of the plaintext, with a value that is equal to the number of padding bytes. Sufficient bytes are added to align the plaintext with the block size of the cipher. For example:
12 34 56 78 9A BC DE F0 08 08 08 08 08 08 08 08
Where the 08 values are eight bytes of padding to align with the AES block size. So, if you decrypt some plaintext is it likely to result in valid padding? Probably not. But it could and so it is a sloppy way to design your system.
You need to add another layer to your proposed protocol to indicate whether the data is encrypted or not. It may also be useful at this point to specify the algorithm used, as this might give you more flexibility in the future to support additional algorithms.

Java - Converting string into DES key

I have been given a key as a string and an encrypted file using DES. That is all I know. I don't know how the key was encoded.
There is also a des.exe that I can use to decrypt, this is all I found on the Internet: http://knowledge-republic.com/CRM/2011/07/how-to-decrypt-extract-recreate-thecus-storage-firmware/
Using des.exe, the only command it works with is "-D", not "-d".
My goal is to use Java to do the same thing. I copied and pasted this from somewhere
String key = "blah";
DESKeySpec dks = new DESKeySpec(key.getBytes());
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
SecretKey desKey = skf.generateSecret(dks);
System.out.println(desKey);
Cipher cipher = Cipher.getInstance("DES"); // DES/ECB/PKCS5Padding for SunJCE
if (mode == Cipher.DECRYPT_MODE) {
cipher.init(Cipher.DECRYPT_MODE, desKey);
CipherOutputStream cos = new CipherOutputStream(os, cipher);
doCopy(is, cos);
}
and it doesn't work.
What are some other options in converting a string into a key?
Should probably add I'm a complete newb at cryptography.
The SunOS man page for des (which seems to be what your des.exe is based on?) indicates that they key is generated like this:
The DES algorithm requires an 8 byte key whose low order bits are assumed to be odd-parity bits. The ASCII key supplied by the user is zero padded to 8 bytes and the high order bits are set to be odd-parity bits. The DES algorithm then ignores the low bit of each ASCII character, but that bit's information has been preserved in the high bit due to the parity.
It also mentions that the initial IV is always zero'd out, no matter what mode you are running in
The CBC mode of operation always uses an initial value of all zeros
for the initialization vector, so the first 8 bytes of a file are
encrypted the same whether in CBC or ECB mode.
It also mentions that the padding used is such that the last byte is always a value from 0-7, indicating the number of padding bytes used. This is similar to PKCS5Padding, so perhaps that would work
Since the CBC and ECB modes of DES require units of 8 bytes to be
encrypted, files being encrypted by the des command have 1 to 8 bytes
appended to them to cause them to be a multiple of 8 bytes. The last
byte, when decrypted, gives the number of bytes (0 to 7) which are to
be saved of the last 8 bytes. The other bytes of those appended to the
input are randomized before encryption.
Based on the options you indicated you are using, it sounds like you are using DES/CBC/PKCS5Padding for the cipher.
I think that just leaves determining how to actually derive the key. I found this sample code on exampledepot which might work for you. I think you would just need to convert your string password into 8 bytes (1 byte per character, so no UTF encodings) then stuff it through the code in the example to derive the key. Its worth a shot anyway.
DES keys are 7 (apparently SunJCE uses 7?) or 8 bytes. Check if the string you have been provided is 7 or 8 bytes. If so, then the chances are good it's the raw key. If not, it could be encoded in some fashion. A giveaway for hex encoding would be a prefix of 0x or suffix of h, and all characters would be in the range 0-9,A-F. You can certainly convert from hex yourself or use some code on the web, but I usually use an Apache commons lib (http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Hex.html).
That said, this is really speculation and I'm not sure we can jump to the conclusion that it's a problem with the key alone. Do you have any other info on the purported encryption algorithm? If the executable you cited works with "-d" then it seems like the encryption is plain DES in CBC mode:
-b : encrypt using DES in ecb encryption mode, the defaut is cbc mode.
(there are multiple possible modes, see http://download.oracle.com/javase/1.4.2/docs/guide/security/jce/JCERefGuide.html#AppA)
I would try setting your cipher to "DES/CBC".
Then again, I'm not sure how to interpret this:
Default is tripple cbc
You may be able to use this snippet to tell what ciphers are available on your system: http://www.java2s.com/Code/Java/Security/ListAllProviderAndItsAlgorithms.htm
I had the same issue with C#. I solved it in the end. You can have a look at my answer here: DES Initialization Vector in C#
Generally, what des.exe does, is that it computes a checksum using DES. So each encryption step is using the previous result instead of advancing in the output array.

Categories