OpenPGPJS: Error decrypting message: No symmetrically encrypted session key packet found - encryption

Below is my simple code (trying to learn how PGP works):
requirejs(['./openpgp'], function(openpgp) {
openpgp.initWorker({
path: './openpgp.worker.js'
});
openpgp.config.aead_protect = true;
var fileContents = "Hello world!!";
var encryptionCode = function(e) {
var options;
var encrypted;
var myKey = {};
myKey.pubkey =
`-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBFjMFRwBCACtu5EG8GusNpr5O4wrb3fykjPegUh9KD/ErWrplmXcbtp6T/XH
FPkc5cyMme7PxxlcFy3fshMDPg0adTGi8/TPygmO9THtjHYqynge0hxDyafP39xE
2DKkyuLyV3KxNiUfr+NUB3MQHktqiS/pPK1MJUQdHjYPHax5QT1bMgffx36tM5vo
d3rdu4AMmLgnSlakmWus/hHMFUgXdp4Q0LWf7uVTXTwbnTkfLQOumj+1SiYV40BL
rxgiyW172uqy6/hqK9JgOvAUjWZiO9aNyexENzA8Y+Oyy3OWX91CKTYiE2eQKhFK
YlTf/AFgrnFd0wgAFkZ0dWj51x7kH1a1Ks8/ABEBAAG0DXJhdmlAdGVzdC5jb22J
ARwEEAECAAYFAljMFRwACgkQc0zV1uezYVSN8Qf+NYyVvKK2HbF+Qn7j+Ed0esK2
OS6xVqdlFfUSAUq1ER13ffc4Darj9Z2LJuOvQ4M11IYlorXGdtiay55oT/xoljDr
HHIYzlQ4h6OzOJP6IUxIS0nqtKZCLhvvEYL/vOb/AeOMSo/ZWHD1RjCnpv0vVXki
4U+kAI8+hfI/QQrVco83xWhH0yiO/HH0eHVLkAiAraqv0zTSX6ttpnYDyK+mwLHt
bgWzzjUi1KZrNtR2CLU8nCUjyHLau1bkZnysq7mAAn69VEVAQ833WnKwBG7uIsym
lcZiCtOtIq40kP1wysObkgfLkD37LW3VpzY2i4+wiWa7i8tBYMvm58BYTCLguA==
=Xm9f
-----END PGP PUBLIC KEY BLOCK-----
`;
myKey.privkey =
`-----BEGIN PGP PRIVATE KEY BLOCK-----
lQOsBFjMFRwBCACtu5EG8GusNpr5O4wrb3fykjPegUh9KD/ErWrplmXcbtp6T/XH
FPkc5cyMme7PxxlcFy3fshMDPg0adTGi8/TPygmO9THtjHYqynge0hxDyafP39xE
2DKkyuLyV3KxNiUfr+NUB3MQHktqiS/pPK1MJUQdHjYPHax5QT1bMgffx36tM5vo
d3rdu4AMmLgnSlakmWus/hHMFUgXdp4Q0LWf7uVTXTwbnTkfLQOumj+1SiYV40BL
rxgiyW172uqy6/hqK9JgOvAUjWZiO9aNyexENzA8Y+Oyy3OWX91CKTYiE2eQKhFK
YlTf/AFgrnFd0wgAFkZ0dWj51x7kH1a1Ks8/ABEBAAH/AwMCAqaV72qGxntgHjJJ
u1IAcTFlGt4e5nXAWGz9nMhQ84p4gHPT3wecMFul9Y8f3Xe8E6+bfaqESrtAaw28
UeRK3HpkYOYgcamC/iIMyZ8/GyqI/VrWpu+ola0WnLQUu58HogpHuk8ezb9Lfypq
qQVp3rTd58sT/RG/25cwSl5QDWZcE2CWTFc9SuwjtRlTj++Hw1ckqGQsGpVoGA3G
Gk5lfK06a3GqDzCaoNG5NUUjKEFhxUfOUCOfV2pyUT+9SBc+HoUptJ/csA/kPCB6
8xW3ycAQFLpYIqLcOJ9H3EMb8FIat2fPyaaocs+yIcYI0VLqS46Rhkj4apBQ8X5d
n3xlL32X/0CA5QKt6ybfXI6uHWvjbyyFl6bw8f8V23fyAXBiqLvz1stGtHTt/IWS
4j2MtOVxOumFY+dG2IHfyWfvh561drasQovtwh9diB4k96dnPYFwlG/8WRkhNF3R
Gkjwy0KOkr/LuvY7H9gFhyYDrXmXrcF3lUYxbQqou4V7nYOKynCGs8phWIezFVbN
4W0ew0rU4MqyAMdZ2YGM/hILSc2/RtufNR/nlPTe7mMGto8TjeVE0LTWcVs+I+A9
Iep0zwJLhdDGH5i0TcHPgxO+mzfcU2V5TrzLMuAlz9xZz3PKHlPMd5GV6THAMHM5
ZJB7P7skxC1zHdL0C00BFxG3QpDMKlFqozE2al7rizU0TtpGPWeOFRjThLuG+4wE
k+zj0EYSxsye7JRkpktMaX0DKk5dtSJn8lcFPR425E+clCwAWyd6Nhf0xEGWbRtL
D2OUWU//FQpDNS74+1EWWiEvfkuz9hZDk19KmpB6amiu4nuyzQJvWB8+gNiSNPZs
af95YSRueaPUYwMFTEhXVZGj1ZX0fM6dfxi4BE/JM7QNcmF2aUB0ZXN0LmNvbYkB
HAQQAQIABgUCWMwVHAAKCRBzTNXW57NhVI3xB/41jJW8orYdsX5CfuP4R3R6wrY5
LrFWp2UV9RIBSrURHXd99zgNquP1nYsm469DgzXUhiWitcZ22JrLnmhP/GiWMOsc
chjOVDiHo7M4k/ohTEhLSeq0pkIuG+8Rgv+85v8B44xKj9lYcPVGMKem/S9VeSLh
T6QAjz6F8j9BCtVyjzfFaEfTKI78cfR4dUuQCICtqq/TNNJfq22mdgPIr6bAse1u
BbPONSLUpms21HYItTycJSPIctq7VuRmfKyruYACfr1URUBDzfdacrAEbu4izKaV
xmIK060irjSQ/XDKw5uSB8uQPfstbdWnNjaLj7CJZruLy0Fgy+bnwFhMIuC4
=Qx/K
-----END PGP PRIVATE KEY BLOCK-----`;
options = {
data: fileContents,
publicKeys: openpgp.key.readArmored(myKey.pubkey).keys
};
openpgp.encrypt(options).then(function(ciphertext) {
myKey.encrypted = ciphertext.data;
console.log("Encrypted: ", myKey.encrypted);
options = {
message: openpgp.message.readArmored(myKey.encrypted), // parse armored message
privateKeys: openpgp.key.readArmored(myKey.privkey).keys[0],
"password": "abcd#1234"
};
openpgp.decrypt(options).then(function(plaintext) {
console.log("plaintext", plaintext);
return plaintext.data;
});
});
}(this);
});
I have generated public and private keys from online site. Its just for testing purpose.
I can see that the string has been encoded properly (console.log). But at the time of decryption, it throws exception Error decrypting message: No symmetrically encrypted session key packet found
What I am doing wrong? Please help me.

Eventually, I figured out that, I had to decrypt my private key in order to decrypt the message.
The following code helped me to complete the encrypt/decrypt demo:
options = {
message: openpgp.message.readArmored(myKey.encrypted),
privateKeys: openpgp.key.readArmored(myKey.privkey).keys[0].decrypt('abcd#1234'),
"password": "abcd#1234"
};
openpgp.decrypt(options).then(function(plaintext) {
console.log("Encrypted message got decrypted: ", plaintext.data);
return plaintext.data;
});
Thanks.

Related

How to encrypt data in one instance of Windows and decrypt in different OS instance running on the same system?

This is an extension of How to encrypt data in one app and decrypt it in different Windows app with RSA keys tied to local system?.
From the linked question above, I was able to encrypt/decrypt data between multiple apps under same OS instance (i.e. Windows10). Then I boot into 2nd instance of Windows 10 on the same system as part of dual boot setup. The app in the link above couldn't decrypt data.
I like to accomplish encryption/decryption between applications running in separate Windows 10 instances running on same physical system. I thought persisting a key will save the key in TPM and an app from different OS instance can get to the same key and use it.
Does TPM or CNG stack on Windows10 let you create TPM sealed keys or private keys that only exist in TPM, but can be accessed from any Windows OS instance running on the same system?
On 8/3/2022:
Updated code snippet based on #bartonjs suggestion below. Now it fails to Decrypt throwing an exception that the operation is not supported.
using System;
using System.IO;
using System.Security.Cryptography;
namespace TPMCrypto
{
class Program
{
static byte[] data = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
static byte[] privateKey;
private static byte[] encrypted;
private static byte[] decrypted;
static void Main(string[] args)
{
const string MyKey = "MyRSAKey";
CngKey cngKey = null;
string cmd = args.Length > 0 ? args[0] : "";
try
{
CngProvider theTPMProvider = new CngProvider("Microsoft Platform Crypto Provider");
CngKeyCreationParameters cng = new CngKeyCreationParameters
{
ExportPolicy = CngExportPolicies.None,
KeyUsage = CngKeyUsages.AllUsages,
KeyCreationOptions = CngKeyCreationOptions.MachineKey,
Provider = theTPMProvider,
Parameters =
{
new CngProperty("Length", BitConverter.GetBytes(2048), CngPropertyOptions.Persist),
},
};
if (!CngKey.Exists(MyKey, theTPMProvider, CngKeyOpenOptions.MachineKey))
{
Console.WriteLine("Creating rsaKey");
cngKey = CngKey.Create(CngAlgorithm.Rsa, MyKey, cng);
}
else
{
Console.WriteLine("Opening rsaKey");
cngKey = CngKey.Open(MyKey, theTPMProvider, CngKeyOpenOptions.MachineKey);
}
RSACng rsaKey = new RSACng(cngKey);
//privateKey = rsaKey.Key.Export(CngKeyBlobFormat.GenericPrivateBlob);
//string prvResult = ByteArrayToHexString(privateKey, 0, privateKey.Length);
//Console.WriteLine("\nPrivate key - length = " + privateKey.Length + "\n" + prvResult + "\n");
const string FILE_PATH = #"\temp\tpmtests\encryptedblob.dat";
// Encrypt / decrypt
if (cmd == "readfromfile")
{
Directory.CreateDirectory(Path.GetDirectoryName(FILE_PATH));
encrypted = File.ReadAllBytes(FILE_PATH);
}
else if (cmd == "deletekey")
{
cngKey.Delete();
return;
}
else
{
encrypted = Encrypt(rsaKey, data);
Console.WriteLine("The encrypted blob: ");
Console.WriteLine(ByteArrayToHexString(encrypted, 0, encrypted.Length));
File.WriteAllBytes(FILE_PATH, encrypted);
}
decrypted = Decrypt(rsaKey, encrypted);
bool result = ByteArrayCompare(data, decrypted);
if (result)
Console.WriteLine("Encrypt / decrypt works");
else
Console.WriteLine("Encrypt / decrypt fails");
}
catch (Exception e)
{
Console.WriteLine("Exception " + e.Message);
}
finally
{
if (cngKey != null)
cngKey.Dispose();
}
Console.ReadLine();
}
static bool ByteArrayCompare(byte[] a1, byte[] a2)
{
if (a1.Length != a2.Length)
return false;
for (int i = 0; i < a1.Length; i++)
if (a1[i] != a2[i])
return false;
return true;
}
public static string ByteArrayToHexString(byte[] bytes, int start, int length)
{
string delimitedStringValue = BitConverter.ToString(bytes, start, length);
return delimitedStringValue.Replace("-", "");
}
public static byte[] Sign512(byte[] data, byte[] privateKey)
{
CngKey key = CngKey.Import(privateKey, CngKeyBlobFormat.GenericPrivateBlob);
RSACng crypto = new RSACng(key);
return crypto.SignData(data, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
}
public static bool VerifySignature512(byte[] data, byte[] signature, byte[] publicKey)
{
CngKey key = CngKey.Import(publicKey, CngKeyBlobFormat.GenericPublicBlob);
RSACng crypto = new RSACng(key);
return crypto.VerifyData(data, signature, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
}
public static byte[] Encrypt(byte[] publicKey, byte[] data)
{
CngKey key = CngKey.Import(publicKey, CngKeyBlobFormat.GenericPublicBlob);
RSACng crypto = new RSACng(key);
var result = Encrypt(crypto, data);
return result;
}
public static byte[] Encrypt(RSACng crypto, byte[] data)
{
if (null == crypto)
return null;
var result = crypto.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
return result;
}
public static byte[] Decrypt(byte[] privateKey, byte[] data)
{
CngKey key = CngKey.Import(privateKey, CngKeyBlobFormat.GenericPrivateBlob);
RSACng crypto = new RSACng(key);
var result = Decrypt(crypto, data);
return result;
}
public static byte[] Decrypt(RSACng aKey, byte[] data)
{
if (null == aKey)
return null;
var result = aKey.Decrypt(data, RSAEncryptionPadding.OaepSHA256);
return result;
}
}
}
Update 8/4/22
With padding change above to SHA256, I was able to encrypt/decrypt data using TPM keys within same OS session as well as separate OS sessions of same OS instance.
Then I booted the system using different Windows OS instance on a USB key. Ran the application. It failed with the following call stack.
>TPMCrypto.exe readfromfile
Exception Message: Unknown error "-1073741275".
Exception stack: System.Security.Cryptography.CryptographicException: Unknown error "-1073741275".
at System.Security.Cryptography.NCryptNative.OpenStorageProvider(String providerName)
at System.Security.Cryptography.CngKey.Exists(String keyName, CngProvider provider, CngKeyOpenOptions options)
at TPMCrypto.Program.Main(String[] args) in TPMCrypto\Program.cs:line 37
The app is failing to open TPM KSM and the app is running with admin privs. The same app with "Microsoft Software Storage Provider" was able to open the KSP, it is the TPM it is failing to open KSP.
It is not clear what the error code -1073741275 mean.
While I can't comment on the code in the link, I do know that keys not only persist in TPM for use on the same drive by two OS's, but stores keys for two or more drives. Where you have a Windows install on C: and one on D:, for example. In other words, it should certainly persist for two OS's on the same drive (different partitions).
So the answer to your last question in the post is yes, the TPM stack will let you create more than one key that should persist for use by another Windows OS instance.. I'm only guessing but I think the problem may be that due to the tiny memory of the TPM it can only hold three transient keys at once. It is possible that your app (or something else) is overwriting the key you need to stay persistent when you switch to the other OS?
Mine is an Intel 2.0 TPM but even if yours is not, there's valuable information here that I believe may help:
https://www.intel.com/content/dam/support/us/en/documents/boardsandkits/D915GMH_TPM_QuickRefGuide01.pdf

How to achieve Xamarin.Android Asymmetric Encryption of RSA key?

Here's the code that i have implemented. Click here for errors. Do i have to import any nuget? Help
public string EncryptRSA(string plainText, string publicKeyString)
{
byte[] cipherText = null;
String strEncryInfoData = "";
try
{
KeyFactory keyFac = KeyFactory.getInstance("RSA");
KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKeyString.trim().getBytes(), Base64.DEFAULT));
Key publicKey = keyFac.generatePublic(keySpec);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA");
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
cipherText = cipher.doFinal(text.getBytes());
strEncryInfoData = new String(Base64.encode(cipherText, Base64.DEFAULT));
}
catch (Exception e)
{
}
return strEncryInfoData.replaceAll("(\\r|\\n)", "");
}
Your codes is in java , however, Xamarin using c#
Please use C# way to do RSA encryption.
If you dont mind, use mine
public class RSA {
public RSA() => Provider = new RSACryptoServiceProvider(2048);
public RSA(string key) {
Provider = new RSACryptoServiceProvider(2048);
Provider.FromXmlString(Encoding.UTF8.GetString(Convert.FromBase64String(key)));
}
public RSACryptoServiceProvider Provider;
public string PublicKey() => Convert.ToBase64String(Encoding.UTF8.GetBytes(Provider.ToXmlString(false)));
public string PrivateKey() => Convert.ToBase64String(Encoding.UTF8.GetBytes(Provider.ToXmlString(true)));
public string Encrypt(string meta) => Convert.ToBase64String(Provider.Encrypt(Encoding.UTF8.GetBytes(meta), RSAEncryptionPadding.Pkcs1));
public string Decrypt(string meta) => Encoding.UTF8.GetString(Provider.Decrypt(Convert.FromBase64String(meta), RSAEncryptionPadding.Pkcs1));
}
Usage:
var rsa = new RSA();
var generatePrivateKey = rsa.PrivateKey();
var generatePublicKey = rsa.PublicKey();
var encryted = new RSA(yourKey).Encrypt(yourText);
var decrypted = new RSA(yourKey).Decrypt(yourText);
Note, this class use 2048 bits and Pkcs1 padding as default, you can change it according to your flavor.

AES decryption returning empty string

Hello i'm trying to encrypt and decrypt files (in Uint8Array format) using CryptoJS Library (3.1.2)
This is my code:
var WPAES = {
keySize: 256,
ivSize: 128,
saltSize: 128,
iterations:1000,
encrypt: function(data,passphrase)
{
try
{
var iv = CryptoJS.lib.WordArray.random(this.ivSize/8);
console.log(iv.toString());
var salt = CryptoJS.lib.WordArray.random(this.saltSize/8);
console.log(salt.toString());
var key = CryptoJS.PBKDF2(passphrase, salt, {
keySize: this.keySize/32,
iterations: this.iterations
});
var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.u8array.parse(data), key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
});
var encryptedIv = CryptoJS.enc.u8array.stringify(iv);
var encryptedSalt = CryptoJS.enc.u8array.stringify(salt);
var encryptedArray = CryptoJS.enc.u8array.stringify(encrypted.ciphertext);
var message = new Uint8Array(encryptedIv.length + encryptedSalt.length + encryptedArray.length);
message.set(encryptedIv);
message.set(encryptedSalt, encryptedIv.length);
message.set(encryptedArray, encryptedIv.length+encryptedSalt.length);
return message;
}
catch(e)
{
console.log(e);
return false;
}
},
decrypt: function(data,passphrase)
{
try
{
var iv = CryptoJS.enc.u8array.parse(data.slice(0, this.ivSize/8));
console.log(iv.toString());
var salt = CryptoJS.enc.u8array.parse(data.slice(this.ivSize/8, this.ivSize/8+this.saltSize/8))
console.log(salt.toString());
var encrypted = CryptoJS.enc.u8array.parse(data.slice(this.ivSize/8+this.saltSize/8));
var key = CryptoJS.PBKDF2(passphrase, salt, {
keySize: this.keySize/32,
iterations: this.iterations
});
var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
});
var res = CryptoJS.enc.u8array.stringify(decrypted.ciphertext);
return res;
}
catch(e)
{
console.log(e);
return false;
}
}
}
I'm also use:
CryptoJS.enc.u8array = {
stringify: function (wordArray) {
var words = wordArray.words;
var sigBytes = wordArray.sigBytes;
var u8 = new Uint8Array(sigBytes);
for (var i = 0; i < sigBytes; i++) {
var byte = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
u8[i]=byte;
}
return u8;
},
parse: function (u8arr) {
var len = u8arr.length;
var words = [];
for (var i = 0; i < len; i++) {
words[i >>> 2] |= (u8arr[i] & 0xff) << (24 - (i % 4) * 8);
}
return CryptoJS.lib.WordArray.create(words, len);
}
};
But when i decrypt the file the results is empty. Ialso check the iv, salt and the encrypted message. All seems work except for the decryption that always returns an empty value.
How can i fix this problem?
Thank you!
I solved using:
var decrypted = CryptoJS.AES.decrypt({ciphertext:encrypted}, key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
});
in decrypt function.
Given it a long try and finally got it.
1). CryptoJS uses hex values while java uses bytes for the same String.
2.) The two other factors which need to be same (apart from the key) are initVector and padding.
Considering both above we first have to validate that both Java are CryptoJS and encrypting to the same value given the above parameters are same.
Here is the code for Java
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.Base64;
public class JavaEncryptor {
private static final String key = "aesEncryptionKey";
private static final String initVector = "encryptionIntVec";
public static String toHex(String arg) throws UnsupportedEncodingException {
return String.format("%020x", new BigInteger(1, arg.getBytes("UTF-8")));
}
/**
* Use these hex value in CryptoJS
* #throws Exception
*/
public static void printHexForJS() throws Exception {
System.out.println("HexKeyForJS : "+ toHex(key));
System.out.println("HexInitVectorForJS : "+ toHex(initVector));
}
public static String encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static void main(String[] args) throws Exception {
printHexForJS();
System.out.println(encrypt("MyPlainTextToBeEncrypted"));
}
}
Output of the above program is
HexKeyForJS : 616573456e6372797074696f6e4b6579
HexInitVectorForJS : 656e6372797074696f6e496e74566563
MURKOx14eSOo2vs8ZQyCpXpsoKg8Uzlvyj3byQreVBk=
And then for JS encryption use the HexKeyForJS and HexInitVectorForJS as in below code
var text = "ManishMudgal";
var key = CryptoJS.enc.Hex.parse(HexKeyForJS);
var iv = CryptoJS.enc.Hex.parse(HexInitVectorForJS);
var encrypted = CryptoJS.AES.encrypt(text, key, {iv: iv, padding: CryptoJS.pad.Pkcs7});
console.log(encrypted.toString());
Output of the above JS code should be kBgYcrSxz+kbXRnyKIFmSw==
Which is the same encrypted key generated through Java code
MURKOx14eSOo2vs8ZQyCpXpsoKg8Uzlvyj3byQreVBk=
Now Decryption at Crypto End
CryptoJS.AES.decrypt('MURKOx14eSOo2vs8ZQyCpXpsoKg8Uzlvyj3byQreVBk=', CryptoJS.enc.Hex.parse(HexKeyForJS), {iv: CryptoJS.enc.Hex.parse(HexInitVectorForJS), padding: CryptoJS.pad.Pkcs7}).toString(CryptoJS.enc.Utf8);
Cheers :)

Node js: How to encrypt and decrypt using public-private key pair using crypto module?

I have to write a code in Node js using crypto module (as I am not allowed to use any module apart from MIT licensed). I need to generate a key pair and encrypt some message with the pulic key and decrypt it with private key. The first part i.e generation of key pair is done. I am not getting any clue how to use crypto modue to encrypt and decrypt some message using the same key pair.
This should do what you want:
const { generateKeyPairSync, publicEncrypt, privateDecrypt } = require('crypto');
//generate a key pair RSA type encryption with a .pem format
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
}
});
// print out the generated keys
console.log(`PublicKey: ${publicKey}`);
console.log(`PrivateKey: ${privateKey}`);
//message to be encrypted
var toEncrypt = "my secret text to be encrypted";
var encryptBuffer = Buffer.from(toEncrypt);
//encrypt using public key
var encrypted = publicEncrypt(publicKey,encryptBuffer);
//print out the text and cyphertext
console.log("Text to be encrypted:");
console.log(toEncrypt);
console.log("cipherText:");
console.log(encrypted.toString());
//decrypt the cyphertext using the private key
var decryptBuffer = Buffer.from(encrypted.toString("base64"), "base64");
var decrypted = privateDecrypt(privateKey,decryptBuffer);
//print out the decrypted text
console.log("decripted Text:");
console.log(decrypted.toString());
It generates a key pair that can be used to encrypt and decrypt a message.
In the Node Documentation for the Crypto lib is the following example:
var crypto = require('crypto');
var alice = crypto.getDiffieHellman('modp5');
var bob = crypto.getDiffieHellman('modp5');
alice.generateKeys();
bob.generateKeys();
var alice_secret = alice.computeSecret(bob.getPublicKey(), null, 'hex');
var bob_secret = bob.computeSecret(alice.getPublicKey(), null, 'hex');
/* alice_secret and bob_secret should be the same */
console.log(alice_secret == bob_secret);
This example shows how to compute a shared secret which can then be used with .createCipher() and .createDecipher() as shown below:
var encrypt64 = function(aMsg, aSecret) {
var cipher, tRet;
cipher = crypto.createCipher('aes-256-cbc', aSecret);
tRet = cipher.update(aMsg, 'utf8', 'base64');
tRet += cipher.final('base64');
return tRet;
};
var decrypt64 = function(aMsg, aSecret) {
var decipher, tRet;
decipher = crypto.createDecipher('aes-256-cbc', aSecret);
tRet = decipher.update(aMsg.replace(/\s/g, "+"), 'base64', 'utf8');
tRet += decipher.final('utf8');
return tRet;
};

TrippleDES without base 64 encoding: Given final block not properly padded

I'm trying to encrypt and decrypt a string using TrippleDES algorythm and without using Base64 encoding (my app will be talking to another app that has these requirements). Everything worked beautifully when I was testing stuff using Base64 encoding/decoding, but when I switched to doing it plain-text style (like the app I'm calling requires), everything broke.
I've read this post Given final block not properly padded which says the key is wrong on decoding, but that can't be, because these lines actually pass in the same variables for both the key and transformation:
ecipher = Cipher.getInstance(transformation);
dcipher = Cipher.getInstance(transformation);
ecipher.init(Cipher.ENCRYPT_MODE, key, iv);
dcipher.init(Cipher.DECRYPT_MODE, key, iv);
Also, I've printed out the lengths of both the encoded string and the array, their lengths are multiples of 8.
My output with I'm getting:
originalText: Abcdefgh
number of bites: 16
cryptText: d4167d9e2b3b1b2d1f940bc45099da0a
cryptText.length: 32
cryptText.getBytes().length: 32
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.DESedeCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
Java Result: 1
My full code (slightly modified version of this tutorial http://eternusuk.blogspot.com/2008/09/java-triple-des-example.html):
package com.test.encrypt;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import org.apache.commons.codec.binary.Hex;
public class TrippleDESTest
{
private Cipher ecipher;
private Cipher dcipher;
private String algorithm = "DESede";
private String transformation = "DESede/CBC/PKCS5Padding";
private String keyPhrase = "123456789012345678901234"; //your keyphrase 24 bit
private SecretKey key;
private IvParameterSpec iv;
private static TrippleDESTest cryptoUtil;
private String ENCODING = "UTF-8";
public static TrippleDESTest getInstance() throws Exception
{
if (cryptoUtil == null)
{
cryptoUtil = new TrippleDESTest();
}
return cryptoUtil;
}
private TrippleDESTest() throws Exception
{
DESedeKeySpec keySpec = new DESedeKeySpec(keyPhrase.getBytes());
key = SecretKeyFactory.getInstance(algorithm).generateSecret(keySpec);
iv = new IvParameterSpec(new byte[8]);
ecipher = Cipher.getInstance(transformation);
dcipher = Cipher.getInstance(transformation);
ecipher.init(Cipher.ENCRYPT_MODE, key, iv);
dcipher.init(Cipher.DECRYPT_MODE, key, iv);
}
public String encrypt(String str) throws Exception
{
byte[] utf8 = str.getBytes(ENCODING);
byte[] enc = ecipher.doFinal(utf8);
System.out.println("number of bites: " + enc.length);
return Hex.encodeHexString(enc);
}
public String decrypt(String str) throws Exception
{
byte[] dec = str.getBytes();
byte[] utf8 = dcipher.doFinal(dec);
return Hex.encodeHexString(utf8);
}
public static void main(String[] args) throws Exception
{
TrippleDESTest test = TrippleDESTest.getInstance();
String originalText = "Abcdefgh";
System.out.println("originalText: " + originalText);
String cryptText = test.encrypt(originalText);
System.out.println("cryptText: " + cryptText);
System.out.println("cryptText.length: " + cryptText.length());
System.out.println("cryptText.getBytes().length: " + cryptText.getBytes().length);
System.out.println("decote text: " + test.decrypt(cryptText));
}
}// end class TrippleDESTest
Thanks in advance!
You are performing the hexadecimal encoding in the wrong order. You need to decode the ciphertext, instead of encoding the plain text in your decrypt method.

Resources