I need to implement an RSAES-OAEP PKCS#1 V2.1 attack, using a unix executable oracle and a ASCII format challenge file. The format of challenge ASCII file is
{n}
{e}
{c}
where N (an integer) is a 1024-bit modulus, e (an integer) is the public exponent and c (an
octet string) is the ciphertext corresponding to the RSAES-OAEP encryption of some unknown
plaintext m (an octet string) under the public key (N, e). Note that the plaintext is ASCII text
(i.e., each octet is an ASCII encoded character), and that the RSAES-OAEP encryption will
have used SHA-1 as the hash function and a null label (i.e., in all cases the label is an octet
string of length zero).
The executable represents an RSAES-OAEP decryption oracle: when executed from a BASH
shell using the command
bash$ ./ USER < USER . challenge
it tries to decrypt the ciphertext read from stdin using the private key (N, d). Note that N is
read from stdin (i.e., from the challenge) but d (an integer) is a private exponent embedded
into the oracle (i.e., you do not have access to it).
The challenge file is as follows:
99046A2DB3D185D6D2728E799D66AC44F10DDAEE1C0A1AC5D7F34F04EDE17B96A5B486D95D927AA9B58FC91865DBF3A1685141345CC31B92E13F06E8212BAB22529F7D06B503AAFEEB89800E12EABA50C3F3BBE86F5966A88CCCF5C843281F8B98DF97A3111458FCA89B8085A96AE68EAEBAE270831D41C956159B81D29503
80A3C4043F940BE6AC16B11A0A77016DBA96B0239311AF182DD70E214E07E7DF3523CE1E269B176A3AAA0BA8F02C59262F693D6A248F22F2D561ED7ECC3CB9ABD0FE7B7393FA0A16C4D07181EEF6E27D97F48B83B90C58F51FD40DCDA71EF5E3C3E97D1697DC8E26B694B5CAFE59E427B12EE82A93064C81AAB74431F3A735
57D808889DE1417235C790CB7742EB76E537F55FD49941EBC862681735733F8BB095EDBB3C0DA44AB8F1176E69A61BBD3F0D31EB997071758A5DD850730A1D171E9EC92788EBA358974CE521537EE4A809BF1607D04EFD4A407866970981B88F44D5260D25C9E8864D5FC2AFB2CB90994DD1934BCEA728B38A00D4712AE0EE
Any ideas as to how to proceed for this attack?!
thanks
Anyone to guide me for this?!!!!!!!!!!
The first thing you could try is to find out whether you can apply the attack by
J. Manger from the paper "A Chosen Ciphertext Attack on RSA Optimal Asymmetric Encryption
Padding (OAEP) as Standardized in PKCS #1 v2.0." Crypto 2001.
That means you have to find out what kind of information you can get from the oracle.
I.e. Choose two arbitrary integers m0, m1 such that m1 is a 1024-bit integer smaller than n
and m0 is 1023 or less bits long. If you pass m0^e mod n and m1^e mod n to the oracle do you get a different response? If so then you might be able to apply the attack in the paper above. Otherwise you will have to search for another flaw in the decryption oracle.
Another approach that might work is to try to modify the modulus n. If the oracle really reads the modulus from user supplied input, then it looks like modifying the modulus should work and the attack becomes quite easy. I don't have access to the implementation of the oracle so I can only guess what might be possible. If you can check for any chosen
n',c' whether c'^d mod n' is a valid OAEP encoded plaintext then you decrypting the original message is not all you can do, in fact you can also recover d and hence factor the original RSA modulus.
(Furthermore this would indeed be a very nice puzzle, so I don't want to spoil the fun by giving
a step by step receipe on how to solve it.)
Related
As we can see from the following questions:
Java HmacSHA256 with key
Java vs. Golang for HOTP (rfc-4226)
, Java doesn't really play nicely when using a key in a TOTP / HOTP / HmacSHA256 use case. My analysis is that the following cause trouble:
String.getBytes will (of course) give negative byte values for characters with a character value > 127;
javax.crypto.Mac and javax.crypto.spec.SecretKeySpec both externally and internally use byte[] for accepting and transforming the key.
We have acquired a number of Feitian C-200 Single Button OTP devices, and they come with a hexadecimal string secret which consist of byte values > 127.
We have successfully created a PoC in Ruby for these tokens, which works flawlessly. Since we want to integrate these in Keycloak, we need to find a Java solution.
Since every implementation of TOTP / HOTP / HmacSHA256 we have seen makes use the javax.crypto library and byte[], we fear we have to rewrite all the used classes but using int in order to support this scenario.
Q: Is there another way? How can we use secrets in a HmacSHA256 calculation in Java of which the bytes have values > 127 without having to rewrite everything?
Update
I was looking in the wrong direction. My problem was that the key was represented a String (UTF-16 in Java), which contained Unicode characters that were exploded into two bytes by getBytes(), before being passed into the SecretKeySpec.
Forcing StandardCharsets.ISO_8859_1 on this conversion fixes the problem.
Signed vs. unsigned is a presentation issue that's mainly relevant to humans only. The computer doesn't know or care whether 0xFF means -1 or 255 to you. So no, you don't need to use ints, using byte[] works just fine.
This doesn't mean that you can't break things, since some operations work based on default signed variable types. For example:
byte b = (byte)255; // b is -1 or 255, depending on how you interpret it
int i = b; // i is -1 or 2³² instead of 255
int u = b & 0xFF; // u is 255
It seems to throw many people off that Java has only signed primitives (boolean and char not withstanding). However Java is perfectly capable of performing cryptographic operations, so all these questions where something is "impossible" are just user errors. Which is not something you want when writing security sensitive code.
Don't be afraid of Java :) I've tested dozens tokens from different vendors, and everything is fine with Java, you just need to pickup correct converter.
It's common issue to get bytes from String as getBytes() instead of using proper converter. The file you have from your vendor represent secret keys in hex format, so just google 'java hex string to byte array' and choose solution, that works for you.
Hex, Base32, Base64 is just a representation and you can easily convert from one to another.
I've ran into absolutely the same issue (some years later): we got Feitian devices, and had to set up their server side code.
None of the available implementations worked with them (neither php or java).
Solution: Feitian devices come with seeds in hexadecimal. First you have to decode the seed into raw binary (e.g. in PHP using the hex2bin()). That data is the correct input of the TOTP/HOTP functions.
The hex2bin() version of java is a bit tricky, and its solution is clearly written in the question of the OP.
(long story short: the result of hex2bin you have to interpret with StandardCharsets.ISO_8859_1, otherwise some chars will be interpreted as 2 bytes utf-16 char, which causes different passcode at the end)
String hex = "1234567890ABCDEF"; // original seed from Feitian
Sring secretKey = new String(hex2bin(hex), StandardCharsets.ISO_8859_1);
Key key = new SecretKeySpec(secretKey.getBytes(StandardCharsets.ISO_8859_1), "RAW");
// or without String representation:
Key key = new SecretKeySpec(hex2bin(hex), "RAW");
I'm trying to solve the problem with the decryption in RSA algorithm.
ArrayList<Integer> m=convertTextToInt(str,e,n,listc);
for (int elem1 : m){
System.out.print( elem1+ " ");
}
Here, I'm passing str which is a string from user it will converted to integer numbers in the convertTextToInt method, a number e and n to calculate the cipher text and array list to store the value after calculate the cipher text with the formula
int c= (int)(Math.pow(Coded,e))%n;
listc.add(c);
then i write this in the main, the problem is that whenever i executed this loop it gives the same result which is 144 !!:
System.out.print("plain text is: ");
for (int element : m){
int plain = (int)(Math.pow(element,d))%n;
listp.add(plain);
System.out.print("listp:"+listp);
}
i tried to change the datatype for the plain to double and it gives me another number but not the right number.
my question is : why the formula of the plain text (description) gives me the same and wrong result every time which is 144 ! :(
Near dupe Storing large numbers for RSA encryption in java
You don't give any clue what numbers you are using, but RSA is only secure if you use numbers of at least about 1000 bits (about 330 decimal digits) which absolutely requires BigInteger in Java. Even this is borderline unsafe; current security standards like those for the WWW from CA/browser forum and for the US government from NIST require 2048 bits.
Even for 'toy' numbers (often used in coursework where no actual security is desired) that fit in Java int (9+ decimal digits) or long (18+ digits), the notional 'raw' decryption computation cd does NOT fit. Math.pow is floating-point so it first returns an imprecise (rounded-off) result, and truncating to int or long turns that into a completely wrong and useless result. You should instead do modular exponentiation in stages with each stage modulo n, as explained in Wikipedia linked from the article on RSA.
If you use BigInteger (as you must for non-toy cases) its modPow method already does this.
Also note 'textbook' RSA -- only exponentiation modulo a large semiprime -- is not actually secure in practice. This is also explained briefly in that Wikipedia article, and https://crypto.stackexchange.com/ has dozens of Q&As on the dangers and limitations of textbook RSA and what to do instead. If you actually want security in Java, at least 'desktop' or 'phone' Java (like Android, but not smartcards and embedded devices), the Java Cryptography Extensions already implement RSA correctly, including the additional things you need such as PKCS1 padding.
I am trying to understand OpenSSL encryption. The requirement for me is to decrypt the data encrypted using the below code. It is creating an anonymous ID for receiver. I need to get received ID back.
Based on the documentation I understood encryption is happening using EVP_EncryptFinal. But what is PKCS5_PBKDF2_HMAC_SHA1 doing ?
The code is using KEY and IV.
int create_anon_id(uint32_t recvr_id, uint32_t smartcard_id, const char *hw_id, unsigned char *anon_id)
{
EVP_CIPHER_CTX ctx;
unsigned char ibuf[sizeof(recvr_id) + sizeof(smartcard_id)] = {};
unsigned char obuf[sizeof(ibuf) * 2] = {};
int olen = sizeof(obuf);
/* Convert to big endian. */
recvr_id = bswap32(recvr_id);
smartcard_id = bswap32(smartcard_id);
hw_id = bswap32(hw_id);
/* Fill input buffer with recvr_id | smartcard_id */
memcpy(ibuf, &recvr_id, sizeof(recvr_id));
memcpy(ibuf + sizeof(recvr_id), &smartcard_id, sizeof(smartcard_id));
if (EVP_EncryptInit(&ctx, EVP_des_ede3_cbc(), KEY, IV) == 1)
{
if (EVP_EncryptUpdate(&ctx, obuf, &olen, ibuf, sizeof(ibuf)) == 1)
{
olen = sizeof(obuf) - olen;
if (EVP_EncryptFinal(&ctx, obuf + sizeof(obuf) - olen, &olen) == 1)
{
return PKCS5_PBKDF2_HMAC_SHA1((const char *)obuf, olen, (unsigned char *)hw_id, HW_ID_SIZE, ROUNDS, ANON_ID_BIN_SIZE, anon_id);
}
}
}
}
That code is quite poor, although by bad luck some of the errors are masked by using an input which is exactly one triple-DES data block (64 bits or 8 bytes). If coded correctly the encryption would be done by both EVP_EncryptUpdate and EVP_EncryptFinal; as written the only encryption actually used, of the unpadded block, is done by Update.
But the value returned in anon_id is NOT (JUST) ENCRYPTED. PKCS5_PBKDF2_HMAC[_SHA1] is an implementation of the PBKDF2 algorithm and as used here it computes essentially a slow hash of
recvr_id concatenated with smartcard_id (update: apparently not swapped) then triple-DES encrypted with KEY and IV whatever those are in this code, as the 'passphrase' with
hw_id (update: apparently not swapped, and thus 'accidentally' type-valid) as the salt,
and PRF = HMAC-SHA1 for ROUNDS (update: 10001) iterations
(update) expanded slightly to ANON_ID_BIN_SIZE (22) bytes. (This requires an extra 'pass' of PBKDF2 which actually hurts security; it slows the defender without slowing the attacker.)
PBKDF2 with a decent PRF (HMAC-SHA1 is) is a one-way function and cannot be reversed, as encryption can if you know or guess the key. It is also designed to be costly to bruteforce if the salt and iteration count are chosen well. 32-bits of salt is definitely on the low side, and (update) ROUNDS 10001 is somewhat on the low side but not crazy.
As a better-case example (for you as attacker) if the 32-bit recvr_id and smartcard_id each contain only 16-bits of entropy, and so does hw_id, and ROUNDS was 1000 which was the recommended value when rfc2898 was written at the turn of the century, you'd have to try up to 256 trillion possibilities and a typical desktop computer can do maybe 30 thousand per second in CPU, and with some luck and skill maybe a thousand times that in GPU, so that will take about 3 months.
On the other hand, if the 32-bit inputs are fully entropic and ROUNDS was 1000000, it is impossible with just a computer. If you have a few million dollars to spend on FPGAs (or even better ASICs), and the output of a power plant (or maybe your own hydroelectric dam) to run them, it will still take many millions of years.
Update: with ROUNDS 10001 you are most likely in between these situations, but just where depends strongly on the entropy of the inputs.
And in general this may not produce the desired result anyway. If the output size is less than or even roughly equal to the entropy of the inputs, there will be collisions -- multiple input values (combinations) that produce the desired output, possibly a great many (millions, billions, etc) of such inputs. If you need the original input, rather than merely some input that produces (forges) a known output, you'll need some other method or criteria to select among the possible inputs that bruteforcing finds.
Update: for output 22 bytes with at most 96 bits entropy, this risk is negligible.
I'm developing my own RSA implementation in java. and while encrypting the data I'm encrypting each letter one by one and after calculating m^e mod n I'm getting values greater than 1000 and if i try to convert that value with (char) 1034 I'm getting ? this symbol for each character and I'm not able to decrypt the cipher text back to plain text what can i do please suggest some idea ???
Don't cast to char. You need to encode your value. One possible simple encoding is hexadecimal. Radix-64 (or base64) are frequently used (as in OpenPGP). Another possible choice is base85.
I've got a bunch of 48-bit (6 byte) values that I need to encrypt symmetrically. The two requirements are:
The resulting encrypted value needs to also be 48-bits (6 bytes) long. They key itself can be (and would preferably be) much longer to guard again brute force attacks.
The resulting encrypted value needs to be deterministic, i.e. value A using key B will always produce encrypted value C (we encrypt on the fly and show the encrypted data to the user so need to always show the same value)
All block ciphers I've found have used a minimum block size of 64 and appear to be fixed (you can't use an arbitrary block size). Should I be thinking about a stream cipher?
I'm doing this in Java.
Note: I've seen this question and associated answers but wasn't clear on whether the suggestions would satisfy my 2nd requirement.
Consider format preserving encryption.
(Sorry, I originally misread the requirements thinking it was the INPUT data that needed to be 6 bytes.)
I don't think you can do exactly what you want with standard cryptographic algorithms:
the problem with stream ciphers is that standard ones effectively work by generating a stream of pseudorandom bits from the key and then XORing these bits with the plaintext; effectively this means that you should never use the same stream of bits twice (e.g. if you do, then XORing two ciphertexts gives you the same result as XORing the corresponding plaintexts; and in any case with 48 bits, there are only 2^48 possible bitstreams, so you can just test them all by brute force);
the problem with block ciphers is that there's no standard one as far as I'm aware that has a block size of 48 bits.
Now, that doesn't mean that a 48-bit block cipher couldn't be developed-- and indeed I dare say there are some out there-- just that none of the bog-standard ciphers that have undergone years of scrutiny from the cryptographic community have that block size.
So I would suggest options are:
relax the requirement of a 48-bit ciphertext; for example, TripleDES has a 64-bit block size and is "fairly" secure (equivalent to 112 bit security)[*];
in principle, you could implement your own block cipher with whatever block size you require, sticking as close as you can to a standard design, e.g. a Feistel network following some generally recommended design principles-- as a starting point, see Schneier, "Applied Cryptography", pp. 346ff, "Theory of Block Cipher Design".
The obvious problem with the latter option is that, whist standard block ciphers are generally based on common general principles, they adopt particular design decisions that have been subject to considerable scrutiny; yours presumably won't be.
I would also recommend standing back a bit from the problem (or perhaps explaining a bit more what you're trying to do), because it seems to be based on requirements that would normally go against good security practice (having the same plaintext always encrypt to the same ciphertext is something one would normally specifically avoid, for example). So you could have the best designed Feistel cipher in the world, but introduce some other vulnerability in how you're using it.
[*] TripleDES is generally not recommended because AES gives better security more efficiently (you might like to see some comparative timings of block ciphers that I took in Java to see just how bad it is). However, this might not matter in your particular application.
No, just "pad" your data out with some bytes you don't care about (but which are always the same if that's your requirement) so that you reach the size of a block. (If you're using an appropriate padding mode, then this will be done for you.)
I believe this is what you are looking for
http://web.cs.ucdavis.edu/~rogaway/papers/shuffle.html
This algorithm lets you construct PRP (i.e. arbitrary length block cipher) from secure PRF (e.g. sha256, blake2)
Block cipher in CTR mode has the same issue as a stream cipher.
Without a proper MAC (which require more bytes added) it will susceptible to bit flipping.
And without unique IV (which also require more bytes added) it will be just a broken implementation.
You can use a stream cipher only, if you have a unique salt for every encryption (don't even think about re-using the same salt, as that would be trivial to break).
When you have such unique values (e. g. a sequence number that's already associated with your values), you can use e.g. the stream cipher RC4-drop.
When you don't have such unique numbers already, you probably can't use a stream cipher, because you only have 48 bits for your result (so no space left for the salt.)
As for a block cipher with 48 bits - sorry, I don't know such a cipher, either. Maybe what you can do, is combining four 48 bit values into a 192 bit value, resulting in three 64 bit blocks, encode them, and then split them into four 48 bit values again. (I have no idea, if that would be possible in your situation or not?)
If you have a unique counter / sequence number associated with each plaintext value, then you can just use any block cipher in CTR (counter) mode.
To encrypt value V that is sequence number N under key K:
Expand N to the size of a block;
Encrypt N with the block cipher and key K;
Take the first 48 bits of the result and XOR them with V.
Decryption is the same. The most important thing to remember with this method is:
Never, ever use the same key and sequence number to encrypt two different values.
Sequence numbers must be unique. If your sequence restarts, you must use a new key.
There is a 48-bit block 80-bit key cipher designed in 2009 - KATAN48 (the family version of KTANTAN48 has some key scheduling issue. So far, it was not broken, and has quite high security margins, so it has passed the test of time.
Here's a proposed solution that meets both of your requirements.
What if you use a cipher with a 32-bit block size (such as Skip32) and run it twice, as described below.
You have a 48-bit value to encode, for example:
f2800af40110
Step 1:
Split this into a 32-bit value and a 16-bit value using some method. Here we'll just grab the left 4 bytes and the right 2 bytes (but in practice you could use a secret bitmask, see below).
32-bit value: f2800af4
16-bit value: 0110
Step 2:
Encrypt the first one with a secret key K1, using Skip32 and let's say we get:
Encrypted 32-bit value: b0daf2b9
Step 3:
Split this into two 16-bit values (again you could use a secret bitmask, but for this example we'll grab the left/right two bytes).
Value 1: b0da
Value 2: f2b9
Step 4:
Combine value 1 with the the 16-bit value from step 1 to get a new 32-bit value:
b0da0110
Step 5:
Encrypt the resulting 32-bit value with secret key K2, again using Skip32:
Encrypted 32-bit value: 6135d8f4
Step 6:
Combine this 32-bit value with value 2 from step 3 to get a 48-bit encrypted result.
6135d8f4f2b9
The result is both deterministic and reversible. No two inputs will produce the same output.
Note on splitting/combining values
Steps 1 and 3 above will split a value in a predictable way. I'm not sure if this introduces any weakness, but one alternative is to use a bitmask. If we want to split a 48-bit input number into 32-bits and 16-bits, we could come up with a bitmask, essentially a number with 16 1's that can dictate how we split bits of the input number to get two output numbers, as follows:
INPUT : 111100101000000000001010111101000000000100010000
BITMASK: 001010111001110000100000010001100000011001100000
| | ||| ||| | | || || ||
VALUE 1: 1 0 101 000 0 1 10 00 00 => a860
VALUE 2: 11 1 0 00 0000 010101 110 000000 10 10000 => e015c050
Similarly for steps 4 and 6 you could combine two values by interleaving bits based on a bitmask.
If you use separate bitmasks for each step and separate keys for each step you end up with 2 keys and 4 bitmasks, all of which would be needed to encrypt/decrypt values.
Quick note on Skip32 and it's use cases
"The Skip32 has the uncommon properties of being fast, creating very dissimilar encrypted values for consecutive input values, and producing output of the same size as the input. These make this cipher particularly useful for obfuscating series of sequential integers (e.g. auto-incremented database ids)."
- https://docs.rs/skip32/1.0.5/skip32/
Any thoughts about this approach from someone more experienced with cryptography than I am?