I am getting Invalid key length: 16 bytes on netbeans ide keybyte length is 16
SecretKey deskey = new SecretKeySpec(keybyte, "DESede/ECB/NOPADDING");
//enter code here..
Cipher c1 = Cipher.getInstance("DESede/ECB/NOPADDING");
c1.init(Cipher.ENCRYPT_MODE, deskey);
but the same code works on android
Your cipher algorithm (triple DES) is expecting a 24 byte key but you only give it 16 bytes, it might help to show how you build the key.
Also, you should be aware of the limitations of ECB. As identical blocks are always encrypted to the same result, it can leave ciphertexts less opaque than you might assume. See here for more detail.
Related
I am trying to get the same amount of bytes of the below snippet in Java. I am working with decryption of encrypted strings with known key. However, I am unable to reproduce these two lines of code in Java.
let usrKey: NSData! = (usrKey as NSString).data(using: String.Encoding.utf8.rawValue) as NSData!
let keyBytes = UnsafeMutableRawPointer(mutating: usrData!.bytes)
How can I get the same keyBytes in Java?
What will the equivalent expression of the above in Java language?
What is the behavior of mutating ?
Java code I tried working with and the error below that.
byte [] keyBytes = userKey.getBytes("UTF-8");
SecretKeySpec secret = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, newIvParameterSpec(ivBytes));
byte[] outputBytes = cipher.doFinal(inputBytes);
input 16 bytes
iv 16 bytes
key 32 bytes
ALGORITHM - AES128/CBC/PKCS5Padding
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:991)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2164)
The issue is to find the right way to get the user key (could be short so padded) and create similar 32 bytes (required by the decryption algo) between Swift and Java code.
The Java line
byte [] keyBytes = userKey.getBytes("UTF-8");
should have the same effect as the two Swift lines. The problem is likely outside of the code that you showed in the question. You may want to debug both Swift and Java code to make sure the usrKey matches userKey and that the resulting keyBytes are the same in both Swift and Java.
Please see Apple documentation at https://developer.apple.com/documentation/swift/unsafemutablerawpointer/2427850-init for the meaning of mutating. Also consult Apple documentation for any other API-related questions.
I java 8 installed on client side where I am encrypting my data file using the below technique
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
outputStream = new CipherOutputStream(new FileOutputStream(encryptedFile), cipher);
And now i am decrypting on server side where i have Java 7 installed as per the code below.
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
inputStream = new CipherInputStream(new FileInputStream(encryptedFile), cipher);
outputStream = new FileOutputStream(decryptedFileName);
Doing so give me below error
Caused by: java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:115) [jce.jar:1.7.0_71]
at javax.crypto.CipherInputStream.read(CipherInputStream.java:233) [jce.jar:1.7.0_71]
at javax.crypto.CipherInputStream.read(CipherInputStream.java:209) [jce.jar:1.7.0_71]
Same code works fine when i have same java version (1.7) installed on both side.
How can we fix this so that without changing the java version either of the side
There are a number of possible causes for this issue:
You don't specify how you are getting/generating the key. If your JREs differ in their possession/absence of the JCE Unlimited Strength Jurisdiction Policies, one will support 256-bit AES encryption and the other will only support 128-bit. If you are generating a key based on the available key lengths, this could be causing the keys not to match. Meanwhile, both of your Java 7 environments may have the same level policies installed.
You are not specifying the block cipher mode of operation or padding scheme on either side of the system -- I recommend an AEAD mode like GCM, EAX, or CCM (CTR + CBC-MAC) in conjunction with NoPadding, but even CBC/PKCS5Padding or CTR/NoPadding are better than the default AES/ECB/PKCS5Padding that you will get just by invoking Cipher.getInstance("AES").
You don't explain how you are encoding the cipher text before persisting it and then deserializing it for decryption. Without a safe encoding scheme like hexadecimal or Base64, you may (read: eventually will) encounter encoding issues working with raw binary values.
Once you change from ECB to another mode of operation, you will need to provide the initialization vector (IV) for both encryption and decryption, and transmit the IV alongside the cipher text. The IV does not need to be encrypted in any way, but it must be unique and non-predictable for each message encrypted with the same key. As it is always the block size of the cipher (fixed at 16 bytes/128 bits for AES), simply prepend the cipher text with the IV value and then split it for decryption.
AES (and all symmetric cryptography) uses the same key for encryption and decryption -- there are no public and private keys involved. It could just be a naming issue, but the fact that you are trying to decrypt with publicKey may indicate the wrong key being used. You should verify that both the encryption and decryption keys are byte-identical (same length (16, 24, or 32 bytes) and equal). ECB "decryption" will always "succeed" if the cipher text is an exact multiple of the block size (16 bytes). Then the padding is verified. If you attempt to decrypt a message with the wrong key, you will often (255/256 times) get a padding error. The other case is that the last byte decrypts to 0x01, which is a valid padding value for PKCS #5/#7, so it won't detect a padding error.
Demonstration that AES/ECB/PKCS5Padding is the default on Java 8 (1.8.0_101):
#Test
public void testCipherGetInstanceShouldDefaultToECB() throws Exception {
// Arrange
final String PLAINTEXT = "This is a plaintext message."
final SecretKey key = new SecretKeySpec(Hex.decodeHex("0123456789ABCDEFFEDCBA9876543210" as char[]), "AES")
Cipher unspecified = Cipher.getInstance("AES")
final Cipher EXPECTED_CIPHER = Cipher.getInstance("AES/ECB/PKCS5Padding")
unspecified.init(Cipher.ENCRYPT_MODE, key)
EXPECTED_CIPHER.init(Cipher.DECRYPT_MODE, key)
// Act
byte[] cipherBytes = unspecified.doFinal(PLAINTEXT.getBytes(StandardCharsets.UTF_8))
logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)}")
// Assert
byte[] recoveredBytes = EXPECTED_CIPHER.doFinal(cipherBytes)
String recovered = new String(recoveredBytes, StandardCharsets.UTF_8)
assert recovered == PLAINTEXT
}
I am trying to encrypt data and send them to the server bye using 256 bits blowfish, but I do not know what is the proper provider for the key size. I have tried to change the CFB32 and CFB8 but does not work I have tried iv with 8 16 and 32 but it does not work. I have tried OAEPWithSHA-256AndMGF1Padding also it did not work.
and when I used blowfish/ECB/PKCS1Padding it gave me message that can not find any provider support blowfish/ECB/PKCS1Padding.
// Create a Blowfish key
KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
// Now set the keysize to 256 bits
keyGenerator.init(256);
Key key = keyGenerator.generateKey();
System.out.println("Done generating the key.");
// Create a cipher using that key to initialize it
Cipher cipher = Cipher.getInstance("Blowfish/CFB8/NoPadding");
//Cipher encrypter = Cipher.getInstance("Blowfish/C/NoPadding");
System.out.println("good here");
SecureRandom random = new SecureRandom();
byte[] iv = new byte[16];
random.nextBytes(iv);
IvParameterSpec spec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key,spec);
If you get the "java.security.InvalidKeyException: Illegal key size" when trying to use key size of 256, then you need to to download JCE Unlimited Strength Jurisdiction Policy Files for your JDK/JRE. The unlimited policy will allow you to use key sizes greater than the predefined limits (128 bits for blowfish).
The Oracle JDK 7 unlimited JCE policy can be downloaded here, make sure to read the readme.txt included in the archive and follow the instuctions.
If you get the "java.security.InvalidAlgorithmParameterException: Wrong IV length: must be ??? bytes long" then you have a mismatch between the actual IV array length and the IV length expected by the mode and padding specified in the Cipher.getInstance() argument. For "Blowfish/CFB8/NoPadding" the IV should be 8 bytes long, but in your code you create a 16-bytes long IV array.
If you have some other problems then you should really update your question and specify what the actual problem is and what the actual exception (preferably with the stacktrace) is.
For 256 bit Keysize, need to add JCE jar in project and referred code will work for that.
JCE Jar : http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
BlowfishUtility: https://github.com/NikhilPareek88/BlowfishUtility
Well this is actually a two-parter...
First I need to
read the contents of the file
crypt them into a byte[]
write the byte[] in a file or whatever...
Then the result from #2 or #3 will go into another project. I'm trying to protect our PEM/DER keys.
For decryption, I need to
read the contents of the crypted file as a byte[]
decrypt them into a byte[]
write the decrypted data to a file OR use it instead of a file
Now, I have some basic crypting code
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128); // 192 and 256 bits may not be available
SecretKey secretKey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// By initializing the cipher in CBC mode, an "initialization vector" has been randomly
// generated. This initialization vector will be necessary to decrypt the encrypted data.
// It is safe to store the initialization vector in plain text for later use. You can obtain
// it's bytes by calling iv.getIV().
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
IvParameterSpec iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class);
// IvParameterSpec iv = new IvParameterSpec(IV); //used for the hardcoded one
byte[] encryptedData = cipher.doFinal(data);
and decrypting one as well
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] decryptedData = cipher.doFinal(encryptedData);
System.out.println("decrypted: " + new String(decryptedData));
and the question is:
Given a use-case scenario where one would rarely encrypt something and would distribute crypted keys that are to be decrypted at runtime, what do I need to save apart from the cyphertext?
I know I need to save the IV, but when I did decryption wasn't quite good - which leads me to believe that I need to save the secretKey as well.
Could anyone give me any tips, pointers or general security hints to a better solution? If I need to save the key, the IV and the encrypted data, where should I store them? Maybe hardcode the key and store the IV along the encrypted data? Maybe hardcode both the IV and the key and just store encrypted data in the files?
This isn't about theoretical safety, think of this as the biggest nuissance and inconvenience you can cause to someone that is trying to steal your keys. We all know there's no way I can perfectly hide them.
I pretty much need what this guy started with Decrypting an encrypted file and executing in Java
However if there's a better way of feeding secure data into a PemKeyReader, i'm all ears.
Sharing the key and encrypting something are two completely different things. How to share keys
Having said this, AES with 128bit is fairly strong encryption algorithm than 3DES So what you can do is keep PKI infrastructure in place to exchange AES keys and then Encrypt and Decrypt using them.
Why not RSA? RSA needs to be minimum 512 bit to consider it as strongest and if you increase more bits then it increases time required for encryption and decryption.
SO AES is fast and safe.
Use SecretKeySpec to create key from byte[]
public static void main(String[] args) throws Exception
{
// Initialise secret key with predefined byte array [] like below. I
// have used simple string to array method to generate 16 byte array.
// AES Key must be minimum 16 bytes.
// Now you can put this byte array some where is .SO file.
// Generate new Key using this byte []
// Then you can generate a key using device specific information at
// first boot up.
// Use second key to encrypt data and first key to encrypt the second
// key
// I Hope it clears all the doubts
SecretKey key = new SecretKeySpec("ABCDEFGHIJKLMNOP".getBytes(), "AES");
System.out.println(Arrays.toString(key.getEncoded()));
// Initialise Cipher with AES Algorithm
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Set The Encrypt Mode
cipher.init(Cipher.ENCRYPT_MODE, key);
// Encrypt some bytes
byte[] encrypted = cipher.doFinal("ABCDEFGH".getBytes());
// Print it to vefiry
System.out.println(Arrays.toString(encrypted));
// Get The IV
byte[] iv = cipher.getIV();
System.out.println(iv.length);
// Now why storing you can create structure like [16 IV][Encrypted Data]
// And while decrypting you can read first [16] bytes IV and then
// decrypt remaining bytes
//byte[] iv = new byte[16];
// System.arraycopy(encrypted, 0, iv, 0, 16)
//Copy remaining bytes to decrypt
// set cipher to decrypt mode
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(iv));
// decrypt it
byte[] decrypted = cipher.doFinal(encrypted);
System.out.println(new String(decrypted));
}
Now write an algorithm which will generate byte[] from some random data like device name, user name, random seed etc.
You can add more protection to algorithm source code by writing that algorithm in C and create.SO file and get byte [] using Native calls.
What are the advantages of doing all this?
Event if your so is hacked it will need real time environment to run create key out of it.
Even if some one does crack it the damage will be limited i.e. 1 device
Hacker will have to repeat same with each device which is highly impossible to do.
The I/O aspect of your question is best addressed by reading the "Byte Streams" and "Buffered Streams" sections of the Oracle Java tutorial. You can accumulate the bytes in memory by writing them to a ByteArrayOutputStream, and then using the toByteArray() method to get the bytes as a byte[].
I am facing a very peculiar problem when using RSA encryption/decryption in Java.
Example code:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.genKeyPair();
Cipher enc = Cipher.getInstance("RSA");
enc.init(Cipher.ENCRYPT_MODE, kp.getPublic());
String CipherText = new String(enc.doFinal(PlainText.getBytes()));
System.out.println("CipherText: ") + CipherText);
Cipher dec = Cipher.getInstance("RSA");
dec.init(Cipher.DECRYPT_MODE, kp.getPrivate());
PlainText = new String(dec.doFinal(CipherText.getBytes()));
System.out.println("PlainText: " + PlainText);
As everyone can plainly see: I encrypt the plaintext using the public key, after which I decrypt the ciphertext using the private key.
This code crashes with the following message:
Exception in thread "main" javax.crypto.BadPaddingException: Data must start with zero
I also tried to explicitly use "RSA/ECB/NoPadding", and this fails on decoding period. (Eg the decoded ciphertext doesn't match the original plaintext).
Last but not least, I have tried to perform this when using my own PKCS1.5 padding function ala the PKCS1.5 specs:
EMB = 00 || 02 || RD || 00 || MD
EMB is encoded messageblock of length k
Where RD are 8 random nonzero bytes
MD is max length k = 11, and optionally padded with zero bytes to make EMB length k.
After two days of testing I can only conclude that the RSA algo in Java is flawed or simply not performing what I expect it to perform.
Any suggestions or fixes to the above code are very welcome, as I am completely stumped on why the above code will not simply work as expected.
Don't do this:
String CipherText = new String(enc.doFinal(PlainText.getBytes()));
Two reasons:
It's almost never a good idea to call String.getBytes() without specifying an encoding. Do you really want the result to depend on the system default encoding?
It's definitely never a good idea to treat the result of a binary encryption operation (i.e. opaque binary data) as an encoded string. Encode it in Base64 or hex instead.
You can use Apache Commons Codec to perform the base64 encode/decode operations, or this standalone public domain encoder/decoder.