Decrypt digital sign bouncycastle - java

I'm using code from this answer there is an example how to sign and verify signature, but how could i decrypt this kind of signature using Bouncycastle? There is no such method in java.security.Signature class.

I think that you mean that you are looking for encryption/decryption sample with bouncycastle instead of a signature/verification sample which you are referencing in your question. In order to do it you can use javax.crypto.Cipher class instead of java.security.Signature I give you a simple example using AES algorithm in ECB mode (please note that there are many cipher algorithms, operation modes etc. this sample is only to show the basics):
import java.security.Key;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class CipherBasicSample
{
public static void main(String args[]) throws Exception
{
Security.addProvider(new BouncyCastleProvider());
// text to cipher
String secret = "secret";
// create the key to cipher an decipher
KeyGenerator kg = KeyGenerator.getInstance("AES","BC");
kg.init(128);
SecretKey sk = kg.generateKey();
Key key = new SecretKeySpec(sk.getEncoded(), "AES");
// get a cipher instance
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
// init to encrypt mode
cipher.init(Cipher.ENCRYPT_MODE, key);
// encrypt the text
cipher.update(secret.getBytes());
byte[] secretEncrypt = cipher.doFinal();
System.out.println("Encrypt text: " + new String(secretEncrypt));
// get a cipher instance
Cipher decipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
// init to decrypt mode
decipher.init(Cipher.DECRYPT_MODE, key);
// decrypt the text
decipher.update(secretEncrypt);
byte[] secretDecrypt = decipher.doFinal();
System.out.println("Encrypt text: " + new String(secretDecrypt));
}
}
Furthermore you can check the bc.prov source code where there are some test classes to test different cipher implementations: src code or on gitHub
Hope this helps,

Related

Safely transport SecretKey for encryption/decryption of Password

I am thinking about using ChaCha20-Poly1305 to encrypt/decrypt a password (I need to encrypt/decrypt cannot only hash). But, to use this algorithm we are required to use a Secret Key. However, this is a problem because I am encrypting/decrypting the user's password on their device, so in my DB I just store their encrypted password.
The problem with it, is if the user uninstall my app from their phone or change to a new phone, I would need the same secret key to be able to decrypt the user's password again.
My question is: How do I safely transfer and store this secret key ?
Also, please let me know if you have better alternatives for my problem, such as different encryption algorithm or methods.
Here is a code example with the SecretKey object that I've mentioned:
package com.javainterviewpoint;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class ChaCha20Poly1305Example
{
static String plainText = "This is a plain text which will be encrypted by ChaCha20 Poly1305 Algorithm";
public static void main(String[] args) throws Exception
{
KeyGenerator keyGenerator = KeyGenerator.getInstance("ChaCha20");
keyGenerator.init(256);
// Generate Key
SecretKey key = keyGenerator.generateKey();
System.out.println("Original Text : " + plainText);
byte[] cipherText = encrypt(plainText.getBytes(), key);
System.out.println("Encrypted Text : " + Base64.getEncoder().encodeToString(cipherText));
String decryptedText = decrypt(cipherText, key);
System.out.println("DeCrypted Text : " + decryptedText);
}
public static byte[] encrypt(byte[] plaintext, SecretKey key) throws Exception
{
byte[] nonceBytes = new byte[12];
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305/None/NoPadding");
// Create IvParamterSpec
AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(nonceBytes);
// Create SecretKeySpec
SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "ChaCha20");
// Initialize Cipher for ENCRYPT_MODE
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);
// Perform Encryption
byte[] cipherText = cipher.doFinal(plaintext);
return cipherText;
}
public static String decrypt(byte[] cipherText, SecretKey key) throws Exception
{
byte[] nonceBytes = new byte[12];
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305/None/NoPadding");
// Create IvParamterSpec
AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(nonceBytes);
// Create SecretKeySpec
SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "ChaCha20");
// Initialize Cipher for DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
// Perform Decryption
byte[] decryptedText = cipher.doFinal(cipherText);
return new String(decryptedText);
}
}
For symmetric encryption and decryption, a best practice is use a MASTER KEY which is fixed string or has a fixed algorithm which just you know how to generate it.
You must use this MASTER KEY for encryption and decryption all other keys (name WORKING KEYS) to encrypt/decrypt real data.
If your device has a secure area which you can save your keys safely, you must inject master key on it by another device or by communicating with a server. If it has not, you are in RISK for disclosing keys.
However, if you are the only programmer of the app, you can use a fixed algorithm to generate MASTER key. For example hash(xor( of 1c1c1c with the ID of the device. Now, the device can send a request for getting working keys (by sending its id and mac-block which is encrypted by master key) to a server and you give back the right working keys.
This scenario use in payments by ISO-8583.

Java: SecretKey to String and rebuilding back to SecretKey produces different decryption result

Currently i've created a SecretKey for use in a RC4 encryption for my assignment. After the RC4 encryption i would then convert this key into string and send it to a server via UDP however when i rebuild it on the server side using SecretKeySpec, it would produce a completely different secret key.
I've looked around stackoverflow for solutions but the end would still result in a rebuilt SecretKey being different from my original SecretKey.
I've tried rebuilding the Secret Key from the String format on the client code and the result would still be a different SecretKey compared to the original so i doubt my UDP tranmission has anything to do with the result.
Below are how i went about creating the initial SecretKey for use in a RC4 encryption:
KeyGenerator keygen = KeyGenerator.getInstance("RC4");
SecretKey originalSecretKey = keygen.generateKey();
How i converted the SecretKey to String and rebuilt using SecretKeySpec:
String k = Base64.getEncoder().encodeToString(originalSecretKey.getEncoded());
byte[] decodedKey = Base64.getDecoder().decode(k);
SecretKey rebuiltSK = new SecretKeySpec(decodedKey, "RC4");
When I println "originalSecretKey" and "rebuiltSK" for checking, this is where I realised the rebuilt values are completely different and therefore i wouldnt be able to decrypt any originalSecretKey-encrypted message using the rebuiltSK.
Edit1: Silly me, thank you to "A Developer" and "Daniel" for pointing out that the actual .getEncoded() values of "originalSecretKey" and "rebuiltSK" are the same.
Apologies if I'm missing something extremely basic regarding Key generation and java's cryptography as this is my first time using them. Thank you in advance for your help !
Edit2:
Below is the code i'm currently using for my RC4 encryption and decryption:
public static byte[] encryptRC4(byte[] b, SecretKey k) throws Exception
{
Cipher cipher = Cipher.getInstance("RC4");
cipher.init(Cipher.ENCRYPT_MODE, k);
//Cipher.DECRYPT_MODE when on server program
byte[] encrypted = cipher.doFinal(b);
return encrypted;
}
The code above is the reason why I'm trying to rebuild the secretKey on the server end after receiving it in byte[] from the client.
I've tried running the decryption with the "rebuiltSK" as the SecretKey argument however it doesn't produce the correct plaintext although I've checked the packet.getData() on both client and server to be the same.
Your rebuilding of the SecretKey works like expected and the encryption followed by the decryption retrieves the
original plaintext.
I can only that argue (same as #Daniel) that the key was changed during transmission or the (byte[] with the)
ciphertext was not fully transmitted to the server.
The below full example code shows a complete round with key generation, encryption and decryption.
This is the result:
plaintext equals decryptedtext: true
decryptedtext: my secret
Security warning: The code below uses an UNSECURE algorithm 'RC4' or 'ARCFOUR'.
Please do not copy below code or use it in production - it is for educasional purposes only.
The code does not have any proper exception handling !
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
public class Main {
public static void main(String[] args) throws Exception {
System.out.println("https://stackoverflow.com/questions/63185927/java-secretkey-to-string-and-rebuilding-back-to-secretkey-produces-different-de");
// security warning: the algorithm 'RC4' or 'ARCFOUR' is unsecure and
// should be used for educational purposes only
// do not use this code in production
// key generation
KeyGenerator keygen = KeyGenerator.getInstance("RC4");
SecretKey originalSecretKey = keygen.generateKey();
// encryption
byte[] plaintext = "my secret".getBytes(StandardCharsets.UTF_8);
byte[] ciphertext = encryptRC4(plaintext, originalSecretKey);
// decryption
String k = Base64.getEncoder().encodeToString(originalSecretKey.getEncoded());
byte[] decodedKey = Base64.getDecoder().decode(k);
SecretKey rebuiltSK = new SecretKeySpec(decodedKey, "RC4");
byte[] decryptedtext = decryptRC4(ciphertext, rebuiltSK);
// output
System.out.println("plaintext equals decryptedtext: " + Arrays.equals(plaintext, decryptedtext));
System.out.println("decryptedtext: " + new String(decryptedtext));
}
public static byte[] encryptRC4(byte[] b, SecretKey k) throws Exception
{
Cipher cipher = Cipher.getInstance("RC4");
cipher.init(Cipher.ENCRYPT_MODE, k);
byte[] encrypted = cipher.doFinal(b);
return encrypted;
}
public static byte[] decryptRC4(byte[] b, SecretKey k) throws Exception
{
Cipher cipher = Cipher.getInstance("RC4");
cipher.init(Cipher.DECRYPT_MODE, k);
byte[] decrypted = cipher.doFinal(b);
return decrypted;
}
}

How can I decrypt text encrypted using this code?

I found this code on a website. I can't understand how to decode this. Can you help me?
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
public class AES {
public static String encrypt(String strToEncrypt) throws Exception {
byte[] plaintext = strToEncrypt.getBytes("UTF-8");
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(256);
SecretKey key = keygen.generateKey();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] ciphertext = cipher.doFinal(plaintext);
return Base64.getEncoder().encodeToString(ciphertext);
}
}
Welcome to Stackoverflow. Below you find a full working example of an AES CBC String en-/decryption. Please note that you need to store the randmly created key & initialization vectore securely to (later) encrypted data because otherwise there is (realy) NO way to recover your data. The same key and iv needs to be used for encryption and decryption.
As the key & iv are byte arrays I encoded them to Base64 for a better storage.
Security warning: This is a simple example to demonstrate AES CBC en-/decryption without any proper exception handling.
The code is for educational purposes only and should not be used in production!
result:
AES CBC String Encryption with random key + iv
This is a simple example to demonstrate AES CBC en-/decryption without any proper exception handling.
The code is for educational purposes only and should not be used in production.
save the key and iv securely, without the data it will be NOT possible to decrypt !!
key in Base64-format: Nf41yG0F+MdFQnp3p3mIrWOk+2kxQ/LmyVcHKEKi5sQ=
iv in Base64-format: yICmqsMaIdwsYsUDUsLWnA==
plaintext: The quick brown fox jumps over the lazy dog
ciphertext: PJNEV3H3Zh3TQx7B9jpg29gV59LgJ6baOpNM82dMOpPClJouYnq+hKVUQTDEkkdI
decryptedtext: The quick brown fox jumps over the lazy dog
code:
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
public class AesCbcTextEncryptionRandomKeyIv {
public static void main(String[] args) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
System.out.println("AES CBC String Encryption with random key + iv");
System.out.println("This is a simple example to demonstrate AES CBC en-/decryption without any proper exception handling.");
System.out.println("The code is for educational purposes only and should not be used in production.\n");
String plaintext = "The quick brown fox jumps over the lazy dog";
// generate a random key & initialization vector
byte[] key = new byte[32]; // key for aes 256 encryption, 32 byte length
byte[] iv = new byte[16]; // initialization vector with 16 byte length
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(key);
secureRandom.nextBytes(iv);
System.out.println("save the key and iv securely, without the data it will be NOT possible to decrypt !!");
// convert key & iv in base64 format for storage reasons
String keyBase64 = Base64.getEncoder().encodeToString(key);
String ivBase64 = Base64.getEncoder().encodeToString(iv);
System.out.println("key in Base64-format: " + keyBase64);
System.out.println("iv in Base64-format: " + ivBase64);
// encryption
String ciphertext = encrypt(keyBase64, ivBase64, plaintext);
System.out.println("plaintext: " + plaintext);
System.out.println("ciphertext: " + ciphertext);
// decryption
String decryptedtext = decrypt(keyBase64, ivBase64, ciphertext);
System.out.println("decryptedtext: " + decryptedtext);
}
public static String encrypt(String keyBase64, String ivBase64, String plaintext)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(keyBase64), "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(Base64.getDecoder().decode(ivBase64));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
return Base64.getEncoder().encodeToString(cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)));
}
public static String decrypt(String keyBase64, String ivBase64, String ciphertext)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(keyBase64), "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(Base64.getDecoder().decode(ivBase64));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);
}
}

Python to Java encryption (RSA)

I make encryption on python and try to decrypt it on Java, but always get decryption error
I have part of code for encrypt and decrypt message in JAVA encoded in RSA
For decrypt:
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public class Decrypter
{
public static void main(String[] args)
{
try {
String encoded_data = "PueF1RC5giqmUK9U+X80SwjAjGmgfcHybjjQvWdqHSlua1rv6xr7o6OMutHBU+NRuyCJ3etTQssYOMGiWPITbEC8xr3WG9H9oRRnvel4fYARvQCqsGmf9vO9rXcaczuRKc2zy6jbutt59pKoVKNrbonIBiGN1fx+SaStBPe9Jx+aZE2hymDsa+xdmBSCyjF30R2Ljdt6LrFOiJKaDiYeF/gaej1b7D8G6p0/HBPxiHMWZhx1ZfylSvZ6+zyP0w+MJn55txR2Cln99crGtcdGeBDyBtpm3HV+u0VlW7RhgW5b+DQwjQ/liO+Ib0/ZIPP9M+3sipIwn2DKbC45o0FZHQ==";
byte[] decodeData = Base64.getDecoder().decode(encoded_data);
String publicKeyString = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzN2+mrQRXKshq3k0r06" +
"0/FoWafOCl6fCCyuu/7SejNU95SN2LZyopA3ipamY5MeK1G1XHOhEfkPWcYcgUbz" +
"TdD166nqJGi/O+rNK9VYgfhhqD+58BCmLlNidYpV2iDmUZ9B/cvVsQi96GY5XOaK" +
"xuVZfwrDK00xcOq+aCojQEvMh+gry05uvzfSv9xK3ki5/iCMY62ReWlmrY0B19CQ" +
"47FuulmJmrxi0rv2jpKdVsMq1TrOsWDGvDgZ8ieOphOrqZjK0gvN3ktsv63kc/kP" +
"ak78lD9opNmnVKY7zMN1SdnZmloEOcDB+/W2d56+PbfeUhAHBNjgGq2QEatmdQx3" +
"VwIDAQAB";
KeyFactory kf = KeyFactory.getInstance("RSA");
byte[] encodedPb = Base64.getDecoder().decode(publicKeyString);
X509EncodedKeySpec keySpecPb = new X509EncodedKeySpec(encodedPb);
PublicKey pubKey = kf.generatePublic(keySpecPb);
Cipher cipherDecr = Cipher.getInstance("RSA");
cipherDecr.init(Cipher.DECRYPT_MODE, pubKey);
byte[] cipherDataDecr = cipherDecr.doFinal(decodeData);
String result = new String(cipherDataDecr);
System.out.println("result = "+result);
}catch (Exception e){
e.printStackTrace(System.out);
}
}
}
Unfortunately I can't make changes in this code, so all what I can is make changes in python part. This part work correctly. for check I use this code for encrypt:
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public class Encrypter
{
public static void main(String[] args)
{
try {
String data = "111111111222";
String privateKeyString = "here is my privat key";
byte [] encoded = Base64.getDecoder().decode(privateKeyString);
System.out.println("encoded = "+encoded);
java.security.Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec ks = new PKCS8EncodedKeySpec(encoded);
RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(ks);
System.out.println("privKey = "+privKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, privKey);
byte[] cipherData = cipher.doFinal(data.getBytes());
String card = Base64.getEncoder().encodeToString(cipherData);
System.out.println("data = "+card);
}catch (Exception e){
e.printStackTrace(System.out);
}
}
}
And when I use result from Java code for encrypt and put this result to decrypt Java file - all work's great. I need same encryption part, but writing with python.
Part for encrypt with python
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
data = '111111111222'
privat_key = 'here is my privat key'
key = RSA.importKey(privat_key)
cipher = PKCS1_v1_5.new(key)
encrypted_message = str(base64.b64encode(cipher.encrypt(base64.b64decode(data))), 'utf8')
print(encrypted_message)
So, questions is how I should encrypt message for correct decryption with on Java?
I tried different libs (standard rsa, Pycrypto RSA, PKCS1_OAEP, PKCS1_v1_5) and nothing help me
P.S. I know about wrong way for use keys pair, but it is requirements of the external system
UPDATE:
Using new instance fetch me to the some result. I changed format as Maarten Bodewes said
Cipher cipherDecr = Cipher.getInstance("RSA/ECB/NoPadding");
decryption result:
����2����ٰoܬ���(�RM#�/���u*�d�{���w�b+���v�ݏ[�$�#��xJo�s��F1���X��}���1 ���������t%`�YA/��?�
�ɼej�X�T�+6Y4D��!���
I can't read it, but it's not a Exception, it is good. Try to move this way
UPDATE:
I define that Java used RSA/ECB/PKCS1Padding as default. So I should use same in python
First of all I defined that java
Cipher cipher = Cipher.getInstance("RSA");
expanded in
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
or
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1PADDING");
For RSA no different what is defined in second argument (None or ECB). RSA doesn't use it.
So I need add padding to my encryption in python. Unfortunately PyCrypto hasn`t PKCS1PADDING, so i can't encrypt with this padding.
Next step I found M2Crypto lib https://gitlab.com/m2crypto/m2crypto
This fork worked for python3. just download and build it(instruction in repo)
Than I wrote this code and it works:
import M2Crypto
# read privat key
privatKey = M2Crypto.RSA.load_key('privat.key')
# encrypt plaintext using privat key
ciphertext = privatKey.private_encrypt(data.encode('utf-8'), M2Crypto.RSA.pkcs1_padding)
encrypted_message = str(base64.b64encode(ciphertext), 'utf8')
print(encrypted_message)
That's all. It works for me, and I believe, it can help u.
According to my code, Bouncy uses the padding for signature generation, so I presume that is what is different. You can perform a "raw" decrypt (modular exponentiation) and remove the padding yourself.

Algorithm AES And Algorithm Twofish

I have a project to make an encryption and decryption for string input in java. I've been stucked for a week doing some research in it. I really appreciate if you have sample source code or function method for Algorithm AES and Algorithm Twofish in java that I may use in my project. I really need your help ... hope someone out there could be my savior. Thanks very much.
For AES you can use java's libraries.
The fallowing code will give you an idea to start.
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AES {
public void run() {
try {
String text = "Hello World";
String key = "1234567891234567";
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(text.getBytes());
System.out.println("Encrypted text: " + new String(encrypted));
// decrypt the text
cipher.init(Cipher.DECRYPT_MODE, aesKey);
String decrypted = new String(cipher.doFinal(encrypted));
System.out.println("Decrypted text: " + decrypted);
}catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
AES app = new AES();
app.run();
}
}

Categories