Bouncycastle PBEWITHSHA256AND256BITAES-CBC-BC Javascript implementation - java

I've tried but failed to encode a string in Javascript to decode on a java server. We'd like to use the bouncycastle algorithm PBEWITHSHA256AND256BITAES-CBC-BC to decode serverside.
I've tried using crypto.js to do the encoding using the following code:
var encrypted = Crypto.AES.encrypt("it was Professor Plum in the library with the candlestick",
key,
{ mode: new Crypto.mode.CBC });
var encryptedString = Crypto.util.bytesToHex(Crypto.charenc.Binary.stringToBytes(crypted));
However this doesn't decode correctly on the server, my guess is its something to do with the SHA256 but I can't work out what it would be digesting & can't find any documentation. Does anyone know how to perform the encryption in javascript?

You need to do everything the same at both ends. You need the same key. You need the same mode (CBC) you need the same padding (use PKCS7) and you need the same IV.
Check that the actual key you are using is the same at both ends by displaying the hex, after you have run the passphrase through SHA-256. Check the hex for the IVs as well. Don't use any defaults, but explicitly pick the mode and padding to use.
If you think that it is the PBE/SHA-256 that is going wrong then you might want to look at how your text passphrase is being turned into bytes. Again, check the hex at both sides before it is passed to SHA-256. Converting text to bytes is a common source of errors. You need to be very sure what stringToBytes() is doing and that whatever you are using on the Java side is doing exactly the same.

Related

Security - Generating Auth-Key for users using Base64?

I'm creating a website on which each new user created (that's what I'm doing for now) will have a auth-key generated which is in Base64 encoding. The auth-key is important as almost all actions performed will require the auth-key of the user. The problem started when I read this article on Base64-Padding and created a few users with more or less the same unique-name (the encryption is done using the unique-name and LocalDateTime at which the user is created). I saw that the keys generated are all very similar to one-another. And then I went through a few more resources and found it is extremely easy to decode it.
Ever since I've been wondering what are the security flaws that I'm facing if I use Base64 encoding? How bad is it? How vulnerable the website will be etc.?
Apart from the above questions I want to know when should I be using Base64 encoding and when I should not? Also what should I use if not Base64?
Note: I'm generating auth-key in Java and the encryption is in AES.
Thank you.
In security, use of Base64 is not to encrypt a string you want to keep secret, it is used to encode it.
In Basic Authentication, for example, the intent of the encoding is to encode non-HTTP-compatible characters that may be in a user name, password, or token into those that are HTTP-compatible.
Encoding does not provide any confidentiality, for that you need to encrypt the string.
Think of the encryption as the security bit, and the encoding is the making string play nice with HTTP.
A common approach at generating a token is to first encrypt it, and then encode it.
As the first line of the article you gave tells :
Base64 is a group of similar binary-to-text encoding schemes that
represent binary data in an ASCII string format by translating it into
a radix-64 representation.
As Base64 encoding can be reversed very easily (it has been designed for this) it would be easily to break through your authentication. You shouldn't consider using Base64 encoding or any cipher encryption for your purpose but instead an hash algorithm like MD5, SHA or other because they are, theoretically, non-reversible and unique. Here is an example for MD5 :
public byte[] digestAuthKey(String login, Date d) {
MessageDigest md = MessageDigest.getInstance("MD5");
String key = login + SALT + d.getTime();
return md.digest(key.getBytes());
}
The SALT contant is a randomly generated string that enhanced the security making it harder to break.
To convert the byte array to string see this post

How to ensure the encrypted length are same as the given string

Hi is it possible to encrypt the string with the certain length that i want? for example: i want to encrypt this string BI000001 to something like hex value A3D5F2ARD3(random) fixed it at 10 length. Therefore when user enter this value A3D5F2ARD3, system will based on this value and decrypt it to get back the value BI000001 .
is it possible to do this in java?
I tried a lot of method but all encrypted length are way too long.
I am not aware of any JDK built-in Java encryption method which provides this feature. Then again, I am not an encryption expert, but I guess such a custom feature won't be built in the JDK.
Maybe this discussion is also useful: https://crypto.stackexchange.com/questions/6098/is-there-a-length-preserving-encryption-scheme
Why do you want to preserve size of the string? maybe there is another solution for your problem.
Typically you would use a block cipher such as AES to encrypt data. Block ciphers (as their name suggest) work in blocks of data of a fixed size, for example AES works in blocks of 128 bits. If a block cipher encounters input smaller than the block size it pads it, which is likely why you are seeing the ciphertext larger than the plaintext.
If you want to preserve the length then consider Format Preserving Encryption as mentioned in this question.

RSA_NO_PADDING is different between Java and C++?

In Java ,I use Bouncy Castle encrypt data using padding:
Cipher cipher = Cipher.getInstance("RSA/ECB/NOPADDING");
The Base64 encoded result is :
AAAAAAAAAAAAAAAAA.....H6hBDxOrCI0K8fd13vOYtsKdo4SI3VZTa3...
Ant it won't change every time.
And in C++, I use OpenSSL library to encrypt data :
RSA_public_encrypt(rsa_len, (unsigned char *)str, (unsigned char*)p_en, p_rsa, RSA_NO_PADDING);
The Base64 encoded result is :
bxeeBPfFRJsLOzJLMS/qGKtDe1zPw8H491QsE+uuRRay6/ep69fqv386j8...
And it will change every time I run code.
I read Wiki and know RSA encryption is a deterministic encryption algorithm.
So the result of java is reasonable and my question is:
Is "AAAAAAAA..." padding is correct for no padding of java?
What has openssl done in C++ code to cause the result seems to have padding and time varying?
Update
I found that my java code is correct.
And When calling RSA_private_encrypt with RSA_NO_PADDING, the input must
have the same size as the RSA key modulus. .After I fill my input to 256 bytes , openssl can decrypt the java encrypt result.
So, the question become to:
What has openssl done to fill the input to reach the required length?
Update
At last, I don't have much time to research the OAEP in openssl.And the server use this unsafe way due to history problem. So I fill my input with byte 0.Just like:
This is input //<-----following many ASCII 0 char to reach 256 bytes length
But this will cause the output be the same. Any other code should prevent this in either server and client.
And it will change every time I run code.
Yes. That's due to Optimal Asymmetric Encryption Padding (OAEP).
If you send the same message twice, like Attack at dawn, your adversary who observes the message won't be able to learn anything (or make an educated guess) when he sees the message again. The property is known as semantic security or Ciphertext Indistinguishability (IND-CPA).
Here's a related talk by Dr. Matt Green on PKCS padding versus OAEP padding. Its very approachable: A bad couple of years for the cryptographic token industry.
Is "AAAAAAAA..." padding is correct for no padding of java?
Possibly. I believe its just a string of leading 0x00 bytes that have been Base64 encoded.
What has openssl done in C++ code to cause the result seems to have padding and time varying?
Its using OAEP.
So, the question become to:
What has openssl done to fill the input to reach the required length?
Its using OAEP.
The question may become: why is Java not using it because lack of OAEP means you could leak information for each message encrypted.

Crypto: Signing with Linux/gcrypt, Verifying with Android/Java

I am dealing with an existing system that gets a string in hex format, adds 8 trailing 0's, and signs it using gcrypt. I am trying to make an Android version that can verify the signature. The existing system works and cannot be changed. I cannot, despite a lot of head scratching, make the android version work.
Both ends agree on the value of the data being signed, the bytes of the resulting signature, and the key being used. I suspect the error is in the interpretation of the data being signed, which I honestly don't understand.
Let us say I am signing "A5DA123456789B00000000"
the linux end, in C++, does this:
#define FORMAT "(data\n (flags pkcs1)\n (hash sha1 #%s#))\n"
sprintf(blob, FORMAT, "A5DA123456789B00000000");
gcry_sexp_sscan(&keydata, NULL, blob, strlen(blob));
and then passes keydata as the second argument to gcry_pk_sign.
the android end, in Java, does this:
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(pubkey);
BigInteger bigData = new BigInteger("A5DA123456789B00000000", 16);
sig.update(bigData.toByteArray());
boolean pass = sig.verify();
pass will be false.
I can sign things in Java, and Java says the signature is fine.
We have C code in linux which says the gcrypt signature is fine.
Is there some obscure setting involving pkcs1 that I've missed somewhere? Or something obvious I'm missing? Anyone know?
Thanks in advance!
OK, my thanks to kroot for the significant clue about gcrypt behaviour.
For those that randomly find this question, the problem I had was the code was signing data in a manner which was ... odd ... and not supported by any of the Signature modes in Java. The solution is to user a Cipher object instead. The signature is nothing more than a private-key encrypted hash. To verify it, use the corresponding public key to decrypt the signature and compare the result to the hash of the data being signed.

Symmetric Encryption between .NET and Java

I am using a 3rd party platform to create a landing page, it is a business requirement that I use this particular platform.
On their page I can encrypt data and send it to my server through a request parameter when calling a resource on my site. This is done through an AES Symmetric Encryption.
I need to specify a password, salt (which must be a hex value) and an initialization vector (but be 16 characters).
Their backend is a .NET platform. I know this because if I specify an IV longer than it expects the underlying exception is:
System.Security.Cryptography.CryptographicException: Specified initialization vector (IV) does not match the block size for this algorithm.
Source: mscorlib
So for example, on their end I specify:
EncryptSymmetric("Hello World","AES","P4ssw0rD","00010203040506070809", "000102030405060708090A0B0C0D0E0F")
Where the inputs are: plain text, algorithm, pass phrase, salt, and IV respectively.
I get the value: eg/t9NIMnxmh412jTGCCeQ==
If I try and decrypt this on my end using the JCE or the BouncyCastle provider I get (same algo,pass phrase, salt & IV, with 1000 iterations): 2rrRdHwpKGRenw8HKG1dsA== which is completely different.
I have looked at many different Java examples online on how to decrypt AES. One such demo is the following: http://blogs.msdn.com/b/dotnetinterop/archive/2005/01/24/java-and-net-aes-crypto-interop.aspx
How can I decrypt a AES Symmetric Encryption that uses a pass phrase, salt and IV, which was generated by the .NET framework on a Java platform?
I don't necessarily need to be able to decrypt the contents of the encryption string if I can generate the same signature on the java side and compare (if it turns out what is really being generated here is a hash).
I'm using JDK 1.5 in production so I need to use 1.5 to do this.
As a side note, a lot of the example in Java need to specify an repetition count on the java side, but not on the .NET side. Is there a standard number of iterations I need to specify on the java side which matches the default .NET output.
It all depends on how the different parts/arguments of the encryption are used.
AES is used to encrypt bytes. So you need to convert the string to a byte array. So you need to know the encoding used to convert the string. (UTF7, UTF8, ...).
The key in AES has some fixed sizes. So you need to know, how to come from a passphrase to an AES key with the correct bitsize.
Since you provide both salt and IV, I suppose the salt is not the IV. There is no standard way to handle the Salt in .Net. As far as I remember a salt is mainly used to protect against rainbow tables and hashes. The need of a Salt in AES is unknown to me.
Maybe the passphrase is hashed (you did not provide the method for that) with the salt to get an AES key.
The IV is no secret. The easiest method is to prepend the encrypted data with the IV. Seen the length of the encrypted data, this is not the case.
I don't think your unfamiliarity of .Net is the problem here. You need to know what decisions the implementer of the encryption made, to come from your parameters to the encrypted string.
As far as I can see, it is the iteration count which is causing the issue. With all things the same (salt,IV,iterations), the .Net implementation generates the same output as the Java implementation. I think you may need to ask the 3rd party what iterations they are using

Categories