I'm trying to write a Groovy script in order to use it in a JSR223 Sampler in JMeter.
This script should get a String RSA private key and decrypt a message.
This is my code:
// This is what I want to decrypt
def sessionToken = vars.get('SESSION_TOKEN')
def cipher = javax.crypto.Cipher.getInstance('RSA')
def factory = java.security.KeyFactory.getInstance("RSA")
// My string private key
def privateKeyString = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAM+lBL+vbq6FyyaGoZqIyHGAWAEhYAKi0wUvve1bvyHZhxTJLSQUYoqDdxZK1MyLnsy75FWQi+oNMdmRtrq7f4FUM9b11pHq83eT57yTWkAUvOX6r0gF7mdcqEoLSG/TxYU5s0qhwSa07JtOzX/EKWKF4Pfmj8+Flagu+hr90MYBAgMBAAECgYEAuITN6YD9/DyMwJmW9fpjFOmWSrrb1LvYhZ1dS5XiDTR+o2v6nzs2LhyRMNAitfnEje7SA29FxiEfkVW5acrAjBTc9wYXAQKXttkL3Ik4NdhJMoM2dBDs2f28z3dWYpRvvTGalHjL4dN9nOfaq/yzFGzC5XbAb7Jo/PoTfD9hMlkCQQDsrqpivsOKL+QZvZQPvEw1yaRUgnZQq36zCH5JiOojIi7sv8aEENDFzD3nKgIEpvMk9MP/AlOCBbRw2jTayyQbAkEA4JegxHCK92mAL28IZNxroG3gfgmfApijvkxeNIWfJ8d4yuY/1cXPg7/XU+4Pvh/i1pUasSa37uG1ArSEnhjIEwJAK8gHlqqJC1fejvBloh+HzW9WaZeUgUmn70BD9CBSh1s8aOj0tNtTczNbxBYeN3QWiCCK3PI2NlgNz85ddpebPwJAKy+88Ekbz7tvtK9LE+n2oCDAvDupYdxsEBmrO7o+Am4u4gUoXTjuUE1BYJg0WsDS46REP7BMShkIr356ydPGFQJAFzC0H3saS2yq7Hs3vXMIbTESI0ro5OAJcgCqBE6sbGqb7MqoTvewtww311Dn0ndXficV1Ihv4I18wdh1kg9Bfg=="
def keyBytes = Base64.getDecoder().decode(privateKeyString.getBytes());
def encodedKeySpec = new java.security.spec.PKCS8EncodedKeySpec(keyBytes)
def privateKey = factory.generatePrivate(encodedKeySpec)
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, privateKey)
cipherText = cipher.doFinal(sessionToken.getBytes())
log.info('SESSION TOKEN Decrypted: ' + cipherText)
After I'm running my code, I got an error:
javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes
I'm not sure what I'm doing wrong :(.
Extra info: I don't have Groovy / Java programming experience.
Thank you!
With help from #Topaco (thank you!) I was able to make the script to work.
Firstly I had to decode my message:
def sessionBytes = Base64.getDecoder().decode(sessionToken.getBytes());
Then I had to add the padding to the chiper:
def cipher = javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1Padding")
And in the end I had to decode my result from cipher:
def string = new String(Base64.getDecoder().decode("YOUR STRING HERE".getBytes()));
Final script:
def sessionToken = "N9Tuh2bvXAQulujXQpSq5xJne+hNaUrsue0X1eOccPxZNhCwWt9/7yXgNv6eULRjCv1fiuuBQ3AchJU2qQp7/PuszHqYYzr6G8k0sYsB2oYR226+so5Ntsnaq61JUr461/jtoxnE3P9hqKwz4NIXjhlB78oVhWsOLeVx69wRuGY="
def sessionBytes = Base64.getDecoder().decode(sessionToken.getBytes());
def cipher = javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1Padding")
def factory = java.security.KeyFactory.getInstance("RSA")
def privateKeyString = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKHn8nN2NDU0oP+hEfa1GOie2hVo57MHC76q6/e/yrfLDgH71zIjThZF9CZLHutw0kD2v2bcvsd5AkGqsAj4AvTRqcuNrNQ+AMtYsphhO8DkZoedOHkOnZ6rkAl7NOF7kUBfamR8ztJdtVnA+LTqzzMMaXgylDopHGZg9JN5ScSPAgMBAAECgYBT6VDBAqxAPwyKMEKNKILGXT4OBpa/NJGjuhYeCyrXYsfZw1pew+l+pbbJ+fkGcSynOrssZpAB9fdzbTFbFJ8CyzK1jQPptxMjo37aKxZI9lKVVOgr/pLX13H/61EjTnFOJwcOV6r6I8LQn5ag+qZjb4KE/N+1zT1prvII3iDTgQJBAOMp/NuiG7QQDV9SGgCjNYc37la9BnMIVsVPIfJc5nbI8dKoxrYO1nIN0IQgDbc5H4smybtONeplXia+KVbSzW8CQQC2dU9xlwXvk8am44x08TVsUdQ7sWunLwgPLiwgPOkhDnTODB3DbHnjNLNCuxLo8e+Vp+JHi1YaqgQzMLP3ISrhAkEAn3LMYpnR2jzeNgcZ61Kj8uqmZ8m8aifzSAF4cXcV6VC4tMX03LtjeKELuIILPo1g/7pVJR0LqSBHyuf1elTzDwJBALRjwwmQwKOevLZfHoy3tZPES0pBHSgLTbKEecfdsLen7T+RpxOA+fjyL5D4F7gLCk4xz3vgfF6cXM6nhiX8usECQQC37mWgTd80UFuw0SYb+gGUzu4+zhvtRzQ3EOLYzAcSVm05lWIpIbHQ7YX4Y+xV4c3l60a5Kds4PxuQlLULe2OM"
def keyBytes = Base64.getDecoder().decode(privateKeyString.getBytes());
def encodedKeySpec = new java.security.spec.PKCS8EncodedKeySpec(keyBytes)
def privateKey = factory.generatePrivate(encodedKeySpec)
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, privateKey)
cipherText = cipher.doFinal(sessionBytes)
def encodedSessionToken = cipherText.encodeBase64().toString()
def decodedSessionToken = new String(Base64.getDecoder().decode(encodedSessionToken.getBytes()));
println decodedSessionToken
Related
So, i tried making a banned word system using sqlite3, but i've ran into a issue and it doesn't error at all nor does it work
My code: ( yes i imported sqlite3 ) & the formatting is correct, its just the code it self
#commands.Cog.listener()
async def on_message(self, member):
db = sqlite3.connect('.//SQL//bannedwords.sqlite')
cursor = db.cursor()
cursor.execute(f'SELECT msg FROM bannedwords WHERE guild_id = {message.guild.id}')
result = cursor.fetchone()
if result is None:
return
else:
cursor.execute(f"SELECT msg FROM main WHERE guild_id = {member.guild.id}")
result = cursor.fetchone()
await message.author.delete()
embed=discord.Embed(title="Blacklisted Word", description="Test")
await message.send(embed=embed, delete_after=7.0)
#commands.group(invoke_without_commands=True)
async def add(self, ctx):
return
#add.command()
async def word(self, ctx, channel:discord.TextChannel):
if ctx.message.author.guild_permissions.administrator:
db = sqlite3.connect('.//SQL//bannedwords.sqlite')
cursor = db.cursor()
cursor.execute(f'SELECT msg FROM bannedwords WHERE guild_id = {ctx.guild.id}')
result = cursor.fetchone()
if result is None:
sql = ("INSERT INTO bannedwords(guild_id, msg) VALUES(?,?)")
val = (ctx.guild.id, msg)
await ctx.send(f"h")
elif result is not None:
sql = ("UPDATE bannedwords SET msg = ? WHERE guild_id = ?")
val = (msg, ctx.guild.id)
await ctx.send(f"added")
cursor.execute(sql, val)
db.commit()
cursor.close()
db.close()
I am aware that i put a text channel, but i don't think thats the only issue - or rather i'm not too sure on what do i replace it with for it to detect messages that are in the msg column
Use message.channel.send instead of message.send.
I have implemented Secure Web hook features for my Spring Boot application(Java).
For that I have created "Subscription" with below JSON.
String subscriptionMessageTemplate = "{\"changeType\": \"created,updated\",\"notificationUrl\": \"%s/notify/messages\",\"lifecycleNotificationUrl\":\"%s/notify/messages/lifeCycle\", \"resource\": \"/teams/{id}/channels/19:{id}#thread.skype/messages\", \"clientState\": \"secretClientValue\",\"includeResourceData\": true,\"encryptionCertificate\": \"%s\",\"expirationDateTime\":\"%s\",\"encryptionCertificateId\": \"1\"}";
I have used ngrok for public IP:
When I am sending message from the team, I am getting below response.
{
"value": [
{
"subscriptionId": "76222963-cc7b-42d2-882d-8aaa69cb2ba3",
"changeType": "created",
// Other properties typical in a resource change notification
"resource": "teams('d29828b8-c04d-4e2a-b2f6-07da6982f0f0')/channels('19:f127a8c55ad949d1a238464d22f0f99e#thread.skype')/messages('1565045424600')/replies('1565047490246')",
"resourceData": {
"id": "1565293727947",
"#odata.type": "#Microsoft.Graph.ChatMessage",
"#odata.id": "teams('88cbc8fc-164b-44f0-b6a6-b59b4a1559d3')/channels('19:8d9da062ec7647d4bb1976126e788b47#thread.tacv2')/messages('1565293727947')/replies('1565293727947')"
},
"encryptedContent": {
"data": "{encrypted data that produces a full resource}",
"dataSignature": "<HMAC-SHA256 hash>",
"dataKey": "{encrypted symmetric key from Microsoft Graph}",
"encryptionCertificateId": "MySelfSignedCert/DDC9651A-D7BC-4D74-86BC-A8923584B0AB",
"encryptionCertificateThumbprint": "07293748CC064953A3052FB978C735FB89E61C3D"
}
}
],
"validationTokens": [
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSU..."
]
}
Now I want to decrypt data, Can any one help me to how to decrypt data in Java?
For certificate generation, I have used my custom method:
strong text.
private void generateSelfSignedX509Certificate(KeyPair keyPair) throws Exception {
// yesterday
Date validityBeginDate = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
// in 2 years
Date validityEndDate = new Date(System.currentTimeMillis() + 2 * 365 * 24 * 60 * 60 * 1000);
// GENERATE THE X509 CERTIFICATE
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
X500Principal dnName = new X500Principal("CN=John Doe");
certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setSubjectDN(dnName);
certGen.setIssuerDN(dnName); // use the same
certGen.setNotBefore(validityBeginDate);
certGen.setNotAfter(validityEndDate);
certGen.setPublicKey(keyPair.getPublic());
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
this.certificate = certGen.generate(keyPair.getPrivate(), "BC");
}
I had to struggle my way with it in Python 3.6, so for the sake of future python-readers, here is my skeleton of working code that do the above (using pycryptodome==3.9.7):
import json
import hashlib, hmac
from base64 import b64decode, b64encode
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Util.Padding import unpad
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES
...
...
encrypted_symmetric_key: bytes = b64decode(encrypted_symmetric_key.encode())
encrypted_payload = b64decode(encrypted_payload.encode())
rsa_key = RSA.import_key(private_key, passphrase=private_key_passphrase)
cipher = PKCS1_OAEP.new(rsa_key)
# if length of encrypted_symmetric_key is > 128 we will get ciphertext with incorrect length, to avoid that lets split and decrypt in chunks
default_length = 128
length = len(encrypted_symmetric_key)
if length < default_length:
decrypt_byte = cipher.decrypt(encrypted_symmetric_key)
else:
offset = 0
res = []
while length - offset > 0:
if length - offset > default_length:
res.append(cipher.decrypt(encrypted_symmetric_key[offset:offset + default_length]))
else:
res.append(cipher.decrypt(encrypted_symmetric_key[offset:]))
offset += default_length
decrypt_byte = b''.join(res)
decrypted_symmetric_key = decrypt_byte
hash_state_machine = hmac.new(decrypted_symmetric_key, msg=encrypted_payload, digestmod=hashlib.sha256)
raw_signature = hash_state_machine.digest()
actual_signature_bytes: bytes = b64encode(raw_signature)
actual_signature: str = actual_signature_bytes.decode()
if actual_signature != expected_data_signature:
raise Exception("data hash is not as expected")
iv = decrypted_symmetric_key[:16]
cipher2 = AES.new(decrypted_symmetric_key, AES.MODE_CBC, iv=iv)
message_str = unpad(cipher2.decrypt(encrypted_payload), block_size=16).decode()
message_dict = json.loads(message_str)
I updated the documentation to include Java samples. I'll also include the samples here for reference but future readers should refer to the documentation which is where the samples will be kept up to date.
Keep in mind these samples operate under the assumption that you have a local Java Key Store (JKS) that the certificate is pulled from.
Decrypt the AES key:
String storename = ""; //name/path of the jks store
String storepass = ""; //password used to open the jks store
String alias = ""; //alias of the certificate when store in the jks store, should be passed as encryptionCertificateId when subscribing and retrieved from the notification
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(storename), storepass.toCharArray());
Key asymmetricKey = ks.getKey(alias, storepass.toCharArray());
byte[] encryptedSymetricKey = Base64.decodeBase64("<value from dataKey property>");
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, asymmetricKey);
byte[] decryptedSymmetricKey = cipher.doFinal(encryptedSymetricKey);
Verify the data signature
byte[] decryptedSymmetricKey = "<the aes key decrypted in the previous step>";
byte[] decodedEncryptedData = Base64.decodeBase64("data property from encryptedContent object");
Mac mac = Mac.getInstance("HMACSHA256");
SecretKey skey = new SecretKeySpec(decryptedSymmetricKey, "HMACSHA256");
mac.init(skey);
byte[] hashedData = mac.doFinal(decodedEncryptedData);
String encodedHashedData = new String(Base64.encodeBase64(hashedData));
if (comparisonSignature.equals(encodedHashedData);)
{
// Continue with decryption of the encryptedPayload.
}
else
{
// Do not attempt to decrypt encryptedPayload. Assume notification payload has been tampered with and investigate.
}
Decrypt the data content
SecretKey skey = new SecretKeySpec(decryptedSymmetricKey, "AES");
IvParameterSpec ivspec = new IvParameterSpec(Arrays.copyOf(decryptedSymmetricKey, 16));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skey, ivspec);
String decryptedResourceData = new String(cipher.doFinal(Base64.decodeBase64(encryptedData)));
optimized the previous answer a bit excluding the hash validations
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from config.config import Config
import base64
import json
config = Config('config.yaml')
notification_response = json.loads(msg)
base64encodedKey = notification_response['value'][0]['encryptedContent']['dataKey']
asymetricPrivateKey = bytes(config.subscription.PRIVATE_KEY,encoding='utf-8')
decodedKey = base64.b64decode(base64encodedKey)
private_key = serialization.load_pem_private_key(
asymetricPrivateKey,
password=None,
backend=default_backend()
)
decryptedSymetricKey = private_key.decrypt(
decodedKey,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(),
label=None
)
)
encrypted_payload = base64.b64decode(notification_response['value'][0]['encryptedContent']['data'].encode())
iv = decryptedSymetricKey[:16]
cipher2 = AES.new(decryptedSymetricKey, AES.MODE_CBC, iv=iv)
message_str = unpad(cipher2.decrypt(encrypted_payload), block_size=16).decode()
message_dict = json.loads(message_str)
On web, I'm using CryptoJS for decrypto JS:
CryptoJS.AES.decrypt(inputBase64, key).toString(CryptoJS.enc.Utf8);
Example:
input: "tzfwnxVwE/qNoaWRRfqLp11ZyhB4UtKO+0/Lvv5B7eE="
key: "20190225165436_15230006321670000_15510884759030000"
On flutter I can't find any library to decrypt with a key of any length.
I know "For AES, NIST selected three members of the Rijndael family, each with a block size of 128 bits, but three different key lengths: 128, 192 and 256 bits.
"
But I don't know how to convert any length key to 128 bit format?
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:tuple/tuple.dart';
import 'package:encrypt/encrypt.dart' as encrypt;
String encryptAESCryptoJS(String plainText, String passphrase) {
try {
final salt = genRandomWithNonZero(8);
var keyndIV = deriveKeyAndIV(passphrase, salt);
final key = encrypt.Key(keyndIV.item1);
final iv = encrypt.IV(keyndIV.item2);
final encrypter = encrypt.Encrypter(
encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
final encrypted = encrypter.encrypt(plainText, iv: iv);
Uint8List encryptedBytesWithSalt = Uint8List.fromList(
createUint8ListFromString("Salted__") + salt + encrypted.bytes);
return base64.encode(encryptedBytesWithSalt);
} catch (error) {
throw error;
}
}
String decryptAESCryptoJS(String encrypted, String passphrase) {
try {
Uint8List encryptedBytesWithSalt = base64.decode(encrypted);
Uint8List encryptedBytes =
encryptedBytesWithSalt.sublist(16, encryptedBytesWithSalt.length);
final salt = encryptedBytesWithSalt.sublist(8, 16);
var keyndIV = deriveKeyAndIV(passphrase, salt);
final key = encrypt.Key(keyndIV.item1);
final iv = encrypt.IV(keyndIV.item2);
final encrypter = encrypt.Encrypter(
encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
final decrypted =
encrypter.decrypt64(base64.encode(encryptedBytes), iv: iv);
return decrypted;
} catch (error) {
throw error;
}
}
Tuple2<Uint8List, Uint8List> deriveKeyAndIV(String passphrase, Uint8List salt) {
var password = createUint8ListFromString(passphrase);
Uint8List concatenatedHashes = Uint8List(0);
Uint8List currentHash = Uint8List(0);
bool enoughBytesForKey = false;
Uint8List preHash = Uint8List(0);
while (!enoughBytesForKey) {
int preHashLength = currentHash.length + password.length + salt.length;
if (currentHash.length > 0)
preHash = Uint8List.fromList(
currentHash + password + salt);
else
preHash = Uint8List.fromList(
password + salt);
currentHash = md5.convert(preHash).bytes;
concatenatedHashes = Uint8List.fromList(concatenatedHashes + currentHash);
if (concatenatedHashes.length >= 48) enoughBytesForKey = true;
}
var keyBtyes = concatenatedHashes.sublist(0, 32);
var ivBtyes = concatenatedHashes.sublist(32, 48);
return new Tuple2(keyBtyes, ivBtyes);
}
Uint8List createUint8ListFromString(String s) {
var ret = new Uint8List(s.length);
for (var i = 0; i < s.length; i++) {
ret[i] = s.codeUnitAt(i);
}
return ret;
}
Uint8List genRandomWithNonZero(int seedLength) {
final random = Random.secure();
const int randomMax = 245;
final Uint8List uint8list = Uint8List(seedLength);
for (int i=0; i < seedLength; i++) {
uint8list[i] = random.nextInt(randomMax)+1;
}
return uint8list;
}
Usage
import 'package:app/utils/cryptojs_aes_encryption_helper.dart';
String plainText = 'PlainText is Me';
var encrypted = encryptAESCryptoJS(plainText, "password");
var decrypted = decryptAESCryptoJS(encrypted, "password");
When you pass CryptoJS a string as the key it treats it as a passphrase and generates the key from it using a key derivation function - in this case PBKDF2. It generates a 256 bit key and a 128 bit initialization vector (IV). It then uses those for the encryption/decryption. You also need to find out what chaining method CryptoJS uses (probably cipher block chaining (CBC)) and what padding method it uses (to make sure that the plain text is a round number of 128 bit blocks - probably PKCS#7).
CryptoJS has this "works out of the box" mode, but it isn't particularly clear what it's doing under the hood - you'd need to read the source code or scour the documentation.
When trying to inter-operate between two systems/languages it's best if you remain in charge of things, rather than letting one end make arbitrary decisions. That way you can make sure that you have the settings the same at each end.
So, you might choose to:
Use PBKDF2 to generate a 128 bit key and 128 bit IV from the string
passphrase - with, say, 9999 rounds
Use PKCS#7 padding
Use AES in CBC mode
The pointycastle package supports all the above in Dart. It looks like CryptoJS supports all of those too.
Start with a passphrase and make sure you can generate the same key and IV in JS and Dart. Then move onto creating the ciphers.
Remember, too, never to encrypt two messages with the same key/IV pair. Use a message sequence number, for example, to slightly change the IV for each message.
Sample encrypt using nodejs script:
var key = CryptoJS.PBKDF2("123456", "123456", {
keySize: 256 / 32
});
var iv = CryptoJS.PBKDF2("123456", "123456", {
keySize: 128 / 32
});
var encrypted = CryptoJS.AES.encrypt('my message', key, { iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString();
decript using dart
import 'package:encrypt/encrypt.dart' as aes;
import 'package:crypto/crypto.dart';
import 'package:hex/hex.dart';
import 'package:password_hash/pbkdf2.dart';
void main(List<String> arguments) {
String encrypted = 'HbsmGAigiIWmU3MNZAf8+w==';
final generator = PBKDF2(hashAlgorithm: sha1);
final key = aes.Key.fromBase16(HEX.encode(generator.generateKey("123456", "123456", 1, 32)));
final iv = aes.IV.fromBase16(HEX.encode(generator.generateKey("123456", "123456", 1, 16)));
final encrypter = aes.Encrypter(aes.AES(key, mode: aes.AESMode.cbc, padding: 'PKCS7'));
final decrypted = encrypter.decrypt64(encrypted, iv:iv);
print(decrypted);
}
I am trying to encrypt a string "1" using key = "secret_key" and text "11869021012". Earlier I had written this in nodejs. now I want to port this to python. but here surprisingly both are giving different outputs.
var crypto = require('crypto');
function getBytes (str) {
let bytes = [], char;
str = encodeURI(str);
while (str.length) {
char = str.slice(0, 1);
str = str.slice(1);
if ('%' !== char) {
bytes.push(char.charCodeAt(0));
} else {
char = str.slice(0, 2);
str = str.slice(2);
bytes.push(parseInt(char, 16));
}
}
return bytes;
};
function getIV (str, bytes){
iv = getBytes(str);
if(!bytes) bytes = 16;
for(let i=iv.length;i<bytes;i++) {
iv.push(0);
}
return Buffer.from(iv);
};
function getKey (pwd){
pwd = Buffer.from(getBytes(pwd), 'utf-8');
let hash = crypto.createHash('sha256');
pwd = hash.update(pwd).digest();
return pwd;
};
function createCipherIV (algorithm, input_key, iv_input, text){
let iv = getIV(iv_input);
let key = getKey(input_key);
let cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(text)
encrypted += cipher.final('base64');
return encrypted;
}
output = createCipherIV('aes256', 'secret_key', '11869021012', '1')
console.log(output)
This produces the output:
s6LMaE/YRT6y8vr2SehLKw==
python code:
# AES 256 encryption/decryption using pycrypto library
import base64
import hashlib
from Crypto.Cipher import AES
from Crypto import Random
BLOCK_SIZE = 16
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]
password = "secret_key"
def encrypt(raw, password):
private_key = hashlib.sha256(bytearray(password, "utf-8")).digest()
raw = pad(raw)
iv = b'11869021012\x00\x00\x00\x00\x00'
cleartext = bytearray(raw, 'utf-8')
cipher = AES.new(private_key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(cleartext))
# First let us encrypt secret message
encrypted = encrypt("1", password)
print(encrypted)
This produces the output:
MTE4NjkwMjEwMTIAAAAAALOizGhP2EU+svL69knoSys=
I have used aes256 algorithm here for encrypting message.
Clearly they are very close, but node seems to be padding the output with some extra bytes. Any ideas how I can get the two to interoperate?
First, in a secure crypto system, you should expect the output to be different every time you encrypt, even using the same code. That fact that yours doesn't indicates it's an insecure cipher. Typically this is done by adding a random IV.
Your IV is "11869021012", which is horrible (because it's not random, and not even 16 bytes), but it does seem you're using it the same way in both, so that's fine.
Your password is the SHA-256 of a string, which is a horrible way to create a key, but still, you seem to be doing it the same way in both cases, so that's fine.
Your problem is that the Python code emits the IV followed by the cipher text. Your JS code does not emit the IV; it only emits the cipher text. So you probably meant this in the Python:
return base64.b64encode(cipher.encrypt(cleartext))
Or you need to rework the JavaScript to glue together the IV and the cipher text before Base64 encoding.
I'm trying to make use of Java signatures in a pretty time sensitive setting.
I've come across some interesting behavior when signing data of a few hundred bytes. I am reusing a generated key, but recreating the Signature object each time I sign. The first time the signing happens it takes from anywhere from 50-100ms depending on the machine being used. However, any subsequent times a signature is computed over new data (using the same key) the time is reduced down to 1-2ms. I'm using SHA512 with RSA so I expected it to be heavier.
Can anyone explain why this happens? A test class I am using is pasted below (which is using identical code to my target applictaion).
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
public class MainClass {
public static void main(String args[]) throws Exception {
//Generate key pair
long start = System.currentTimeMillis();
KeyPair keyPair = generateKeyPair(999);
long end = System.currentTimeMillis();
System.out.println("KeyGen: " + (end - start));
//Sign first piece of data
byte[] data = { ** a few hundred bytes** };
start = System.currentTimeMillis();
byte[] digitalSignature = signData(data, keyPair.getPrivate());
end = System.currentTimeMillis();
System.out.println("Sign: " + (end - start));
boolean verified;
byte[] data2 = {** a different few hundred bytes ** };
//sign second piece of data
start = System.currentTimeMillis();
digitalSignature = signData(data2, keyPair.getPrivate());
end = System.currentTimeMillis();
System.out.println(" Second Sign: " + (end - start));
//verify second signature
start = System.currentTimeMillis();
verified = verifySig(data2, keyPair.getPublic(), digitalSignature);
end = System.currentTimeMillis();
System.out.println("Verify: " + (end - start));
System.out.println(verified);
}
public static byte[] signData(byte[] data, PrivateKey key) throws Exception {
Signature signer = Signature.getInstance("SHA512withRSA");
signer.initSign(key);
signer.update(data);
return (signer.sign());
}
public static boolean verifySig(byte[] data, PublicKey key, byte[] sig) throws Exception {
Signature signer = Signature.getInstance("SHA512withRSA");
signer.initVerify(key);
signer.update(data);
return (signer.verify(sig));
}
public static KeyPair generateKeyPair(long seed) throws Exception {
KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom rng = SecureRandom.getInstance("SHA1PRNG", "SUN");
rng.setSeed(seed);
keyGenerator.initialize(1024, rng);
return (keyGenerator.generateKeyPair());
}
}
This results in the output (time in ms)
KeyGen: 81
Sign: 52
Second Sign: 2
Verify: 2
I put some benchmarks on each line of the sign method, and it appears the overhead is purely from the sign action itself.
Create Sig Obj: 1
Init sign: 1
update: 0
Sign: 49
Create Sig Obj: 1
Init sign: 0
update: 0
Second Sign: 2
Any insight would be much appreciated