I want to encrypt a image and then decrypt it. Is there any good references or tutorials or sample showing how to convert the image into a string then encrypt the string? Or there are other ways in encrypting the image? As I am a newbie to this and also I have went to search but there aren't any easy examples for me to understand and also to follow.
If I'm not wrong, i have to use the FileInputstream, and the ImageIO, but i do not know how does it fully works. Anyone can guide me? thanks
An image is a binary file, so I don't think it makes much sense to convert to a String for the purpose of encryption. This would add quite a bit of overhead and complexity for no additional benefit.
You should probably just encrypt the binary file directly.
See:
How to encrypt/decrypt a file in Java?
If your question is "how do I perform encryption in Java", then have a look at some stuff I've written on Java cryptography, in partcular the section on symmetric key encryption. Essentially, you create some secret key, which can just be a string of random bytes generated with SecureRandom:
byte[] key = new byte[16];
(new SecureRandom()).nextBytes(key);
Then you construct a Cipher object and init it with the key, then pass it the data you need to encrypt:
public byte[] encryptData(byte[] key, byte[] data) {
Cipher c = Cipher.getInstance("AES/CTR/PKCS5PADDING");
byte[] initialCounter = new byte[16];
c.init(Cipher.ENCRYPT_MODE,
new SecretKeySpec(key, "AES"),
new IvParameterSpec(initialCounter));
byte[] encryptedData = c.doFinal(plaintextData);
return encryptedData;
}
There's nothing necessarily very special about encrypting an image-- it's just a bunch of bytes like anything else at the end of the day.
The main problem with cryptography is that there are various subtleties that you need to understand for it to be secure.
This link here may also help you out alot:
Using AES with Java Technology
NB you wont need to convert it to a String more like a byte array-
Related
I have encrypted the string in PHP using AES-256-ECB.
$sString = "test"
$sEncryptionMethod = "AES-256-ECB";
$sEncryptionKey = "mysecretkey";
openssl_encrypt($sString, $sEncryptionMethod, $sEncryptionKey)
I would like to decrypt the same using Java/Scala?
String secret = "mysecretkey";
SecretKeySpec skeySpec = new SecretKeySpec(encKey.getBytes("UTF-8"), "AES");
byte[] decodedValue = Base64.getDecoder.decode(token);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
int decryptMode = Cipher.DECRYPT_MODE;
cipher.init(decryptMode, skeySpec);
new String(cipher.doFinal(decodedValue));
I am seeing the following error? how can we decrypt the same using Java?
Note: (decryption in PHP is working as expected) but I want to do this in Java
Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
The key has to be exactly 256 bit long. Clearly the PHP side is doing some unspecified magic voodoo to "mysecretkey" to obtain a 256 bit key. Java does not, as a rule, engage in 'the user does not appear to know what they are doing, eh, I'll take a wild stab in the dark', like PHP does, which is the problem here.
Figure out how "mysecretkey" is turned into a 256-bit key, and replicate that in java.
NB: ECB is extremely insecure. It sounds like you don't know enough about encryption to have any hope of producing an application that is actually hard to trivially break.
NB2: Note that the PHP documentation itself strongly suggests that 'key' should be some cryptographically derived secure source of 256 bits. The fact that openssl_encrypt actually gives you an answer when you provide a broken key is somewhat eyebrow raising. See the various comments at the PHP manual on openssl_encrypt which clearly highlight some weirdness is going on there but none are clear enough to actually explain what PHP is doing here.
I'm using the jpbc java library to achieve the HIBE encryption in order to encrypt and decrypt a String data.
In this case, i found a function that's allowed me to get an Element from a String as it shown below and it make me able to encrypt & decrypt this Element :
private static void elementFromString(Element h, String s) throws NoSuchAlgorithmException
{
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(s.getBytes());
h.setFromHash(digest, 0, digest.length);
}
But now, i need a solution to get the string data from the Element after decryption or any other idea can help me.
Thank you
Hashing is not encrypting. SHA-1 is a one-way function, i.e. you can possibly guess the input given the output, but you cannot retrieve the input by any calculation.
To encrypt and decrypt you need a cipher. A cipher often consists of a block cipher and a mode of operation such as "AES/GCM/NoPadding". Kind of surprising, it is represented by the Java Cipher class.
You may need to generate a key or key pair and store it somewhere, such as a KeyStore.
Trying to perform crypto without understanding what you are doing may result in code that runs - eventually. However, the chances that it will be secure is minimal. First try and learn about the subject.
Note that calling getBytes on a String results in platform specific encoding. This can be fun if you switch platforms in the future. Explicitly specifying UTF-8 is a good idea.
I tried many answers from SO and all over the web but still without success.
I use following tool to encrypt.
text to encrypt: tom
key: exo123exo1exo123
input (textfield or selected file above) is: text/binary
Convert output to: [i leave this unselected]
Mode: CTR
Ciphers: Rijndael-128 and Rijndael-256
After getting result I move here:
and encode it with base64.
Then I copy string and send it as a parameter to my function:
public String authenticate(String base64EncodedData){
byte[] input = Base64.decodeBase64(base64EncodedData);
byte[] ivBytes = "1234567812345678".getBytes();
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
cipher.init(
Cipher.DECRYPT_MODE,
new SecretKeySpec("exo123exo1exo123".getBytes(), "AES"),
new IvParameterSpec(ivBytes)
);
byte[] plainText = new byte[cipher.getOutputSize(input.length)];
int plainTextLength = cipher.update(input, 0, input.length, plainText, 0);
plainTextLength += cipher.doFinal(plainText, plainTextLength);
return new String(plainText);
}
Result I got is always something similar to this (no matter if I use Rijndael-128 or 256 encrypted string):
.�v�Y�
When I try to return input value - I get the encrypted string. So base64 works just fine.
What I do wrong?
Am slowly getting mad here.
Thank you.
There are some problem with your assumptions and your code:
The output of the first tool is already Base 64 encoded. RIJNDAEL-128: r0GR and RIJNDAEL-256: yAVy. It doesn't need to be encoded a second time. It automatically selects this option, because binary data cannot be printed.
There is no native Rijndael-256 in Java, you will have to use BouncyCastle for this. Rijndael-128 is supposed to be AES which means that both have a block size of 128-bit.
The IV almost certainly needs to consist of zero bytes. For example:
byte[] ivBytes = new byte[16];
Arrays.fill(ivBytes, (byte)0); // might not be necessary
Note that CTR mode doesn't use an IV, but rather a nonce.
Always specify an encoding when retrieving bytes: "exo123exo1exo123".getBytes("UTF-8"). It is probably best to use UTF-8 everywhere. If you send data across systems that use different system encodings, it will lead to hard to find problems.
On second look at the online tool is not usable for anything, because it is unclear how it works. What I found:
Any key produces a ciphertext regardless of size, which suggests that the "key" that you enter is actually hashed and there exist a million ways that could be done. I could decrypt it with the above method, so the key is actually uses as-is without hashing. This suggests that the key is filled up with 0x00 bytes until a valid key size. When the key size is too big, it is probably truncated.
Plaintext of 16 characters encrypts to a ciphertext of 16 bytes (encoded 24) and a plaintext of 17 characters encrypts to a ciphertext of 32 bytes (encoded 44). This means that no discernible padding is used which might actually be zero padding.
And here is the deal breaker:
Every time you encrypt something, you get a different ciphertext. In CBC mode it means a random IV is generated before encrypting. The problem is that this IV is not shown. So there is no way to decrypt this fully. So if you encrypt more than 16 characters you can recover all but the first 16 characters when you decrypt it in the way I describe it in the first part of this answer.
You shouldn't make your system dependent on closed source online tools. Write your own encryption tool. Some general advice:
IV should be generated randomly every time you encrypt something. It is not secrect, but should be unique. Simply prepend it to the ciphertext after encryption and slice it off before decryption.
Use an authenticated mode like CCM or GCM where possible. It is harder to do authenticated encryption yourself, but the other way to go would be to use encrypt-then-mac paradigm.
I'm tring to encrypt/decrypt my files using AES. I followed this tutorial to encrypt my data, but I modified the code a little bit, so that I could use the same key to encrypt many files.
In addition to encrypting my files, my AES key is also saved using RSA (this page , saveKey() method).
I encrypted files on my PC, and tried to decrypt them on Android. However, I always got BadPaddingException: pad block corrupted. I printed out the AES keys, and found out that with the same private key, the decrypted AES keys were different on PC and Android.
It worked fine if I decrypt the same files on PC.
Why?!
Is there anything wrong with Android's cipher?! Help needed.
your RSA padding cipher could be on the wrong padding scheme
try this?
pkCipher = Cipher.getInstance("RSA/NONE/PKCS1Padding");
The code you copied is wrong. It may or may not work depending on Android version. My guess is that it doesn't on newer ones. The part which converts from seed to raw key is flawed (see below): SecureSeed.setSeed() is not guaranteed to set the random generator state, it just adds to it. What this means is that you are not guaranteed to get the same key. To reliably get the same key based on a password, you need to use PBE (Password Based Encryption)
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
// this is wrong!
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
Generally, first make sure you can reliably encrypt/decrypt using AES, then you might move on to using RSA. You might want to tell us what you are trying to achieve, you might be going at it the wrong way. Inventing your own cryptographic protocol is rarely a good idea.
I am reading about encryption and having a lot of difficulty understanding these 3 Java statements of an encryption program.
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
encrypted = cipher.doFinal(str.getBytes())
Can somebody help?
In simpler terms,
create a new Encrypting Device using the AES algorithm;
make it ready
get the bytes of the string str and encrypt them; return the result into the encrypted object, whatever that is.
what exactly did you not understand?
cipher = Cipher.getInstance("AES");
Get a Cipher object that can encrypt/decrypt using the AES algorithm. Java's cryptography code is a bit weird - instead of directly creating objects, you generally use a getInstance call with a String argument. (Note that "cipher" means "way of encrypting something".)
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
Tell the cipher that you would like to encrypt something (Cipher.ENCRYPT_MODE), and give it the encryption key skeyspec.
encrypted = cipher.doFinal(str.getBytes())
The way ciphers work is that you feed them chunks of byte data using the update method, which causes the cipher to accumulate the encrypted data within itself. For the final block of data, doFinal is used, which tells the cipher that the encryption process is done. A different method is needed because the cipher often has to pad out the data returned to a particular length. doFinal then returns the final bit of encrypted information.
However, if there is a single readily available chunk of data, you can just call doFinal and it will give you all the encrypted bytes at once. But this explains why the method is called doFinal, not say, "process".
So in summary, the code above creates an AES encryption engine, gives it an encryption key, then uses it to encrypt the String str into the byte array encrypted.
Note that cryptography is very tricky business and very easy to get wrong. There's all kinds of things you need warning about that I haven't touched on because my wrists hurt now. So I would heavily recommend you get a copy of Beginning Cryptography with Java - it's where I learned to understand this stuff.