I'm have a plain JSON text which is encrypted using Triple-DES in Visual Basic(code provided below), now I'm trying to decrypt it using python language. when I test it I'm getting the wrong output.
I think there is any padding issue because I didn't get this line:
ReDim Preserve hash(length - 1)
VB code:
Public NotInheritable Class Simple3Des
Private TripleDes As New TripleDESCryptoServiceProvider
Private Function TruncateHash(ByVal key As String, ByVal length As Integer) As Byte()
Dim sha1 As New SHA1CryptoServiceProvider
' Hash the key.
Dim keyBytes() As Byte = System.Text.Encoding.Unicode.GetBytes(key)
Dim hash() As Byte = sha1.ComputeHash(keyBytes)
' Truncate or pad the hash.
ReDim Preserve hash(length - 1)
Return hash
End Function
Sub New(ByVal key As String)
' Initialize the crypto provider.
TripleDes.Key = TruncateHash(key, TripleDes.KeySize \ 8)
TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8)
End Sub
Public Function EncryptData(ByVal plaintext As String) As String
' Convert the plaintext string to a byte array.
Dim plaintextBytes() As Byte = System.Text.Encoding.Unicode.GetBytes(plaintext)
' Create the stream.
Dim ms As New System.IO.MemoryStream
' Create the encoder to write to the stream.
Dim encStream As New CryptoStream(ms,
TripleDes.CreateEncryptor(),
System.Security.Cryptography.CryptoStreamMode.Write)
' Use the crypto stream to write the byte array to the stream.
encStream.Write(plaintextBytes, 0, plaintextBytes.Length)
encStream.FlushFinalBlock()
' Convert the encrypted stream to a printable string.
Return Convert.ToBase64String(ms.ToArray)
End Function
Public Function DecryptData(ByVal encryptedtext As String) As String
' Convert the encrypted text string to a byte array.
Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedtext)
' Create the stream.
Dim ms As New System.IO.MemoryStream
' Create the decoder to write to the stream.
Dim decStream As New CryptoStream(ms,
TripleDes.CreateDecryptor(),
System.Security.Cryptography.CryptoStreamMode.Write)
' Use the crypto stream to write the byte array to the stream.
decStream.Write(encryptedBytes, 0, encryptedBytes.Length)
decStream.FlushFinalBlock()
' Convert the plaintext stream to a string.
Return System.Text.Encoding.Unicode.GetString(ms.ToArray)
End Function
End Class
Here is my approach with different paddings and combinations:
from pyDes import *
import hashlib
import base64
key = b'Hi4Q=rLJnyqPj$G_cTqDcwgWo'
sha1_hash = hashlib.sha1(key).digest()
key_ = sha1_hash[:len(key)//8]
# key_ = sha1_hash[:-4]
# key_ = sha1_hash
base64Encrypted = r'''...'''
base64Decrypted = base64.b64decode(base64Encrypted)
print ("output: ", k.decrypt(base64Decrypted))
Am I doing something wrong?
Related
ciphertext = base64.b64decode(xxxxxx) //output is b'148,240,50,66,81,26,240,2,101,31'
bytearray(ciphertext) // output is bytearray(b'148,240,50,66,81,26,240,2,101,31')
What am looking for is output of bytearray([148,240,50,66,81,26,240,2,101,31])
Full code:
ciphertext = base64.b64decode("MTQ4LDI0MCw1MCw2Niw4MSwyNiwyNDAsMiwxMDEsMzEsMjM3LDEwMSw4OCwxODQsMTQsMTM1LDEzMCw0Miw0NywxODksMTkyLDE1MSw0OCwyMjQsMTU1LDQxLDM5LDE0MywyMDksMTA0LDE5NywyMywxMDUsMjMsMTYzLDUzLDQsMTQ0LDE2MSwxNDgsMjMwLDI1NCwxMzQsMjEzLDE3NCwyNDcsMTkxLDUyLDY0LDE2LDYzLDk0LDE1NCwxMzMsMzksMTMzLDIyNCwxODcsMTE0LDE1OCwyMzksMzUsMTUxLDM4LDE3NSwxNTIsOTksMTAyLDIxNCwyNTEsMTk0LDIxMywxNzMsMTc0LDcyLDIyNSwyMDIsMTcyLDE1NCw4OCwxMzksMTE1LDIzNywyMzYsMTIxLDAsMjE0LDIxNiwxOTYsNDAsMzgsMjA0LDgzLDEzNiwxNjAsMTczLDY5LDcsMzgsMjI1LDExOCw0OSw0OCw3MCwxNjYsMTIxLDI0NSwxOTEsMTgzLDEyMiwxOTksMTg3LDgsNDMsNDUsOTMsMTI0LDIxNSwxNjEsNzAsMjU0LDI2LDE4OCwxMywyMjYsMTMxLDMsNCw0MywxOTgsMjEyLDEwMywxMTcsMjE1LDEyNywyNDMsMzksNzIsNzYsMTE0LDUwLDE5Niw1NSwxMjEsODYsMjUxLDUzLDI0MiwzMCwxMDksNDcsMjEwLDI1MywxNjMsOTAsOTgsMTQsNjAsMTE1LDc1LDE0OSwyMTAsMTc1LDI2LDEyNCwyMjgsMjQ3LDIwLDIwMyw5NiwyMTAsMjYsODEsNjUsMTg4LDEyMSwxMjgsOTEsMTA3LDE2OCwxMywyMDcsMTc1LDE3MCwyNTUsMjM2LDE0OSwxMDksNTksMjQsMTcyLDExLDU4LDEzLDAsMTUyLDExNiwxMTAsMTExLDIyLDIzMSwzLDIzNyw0Miw4MSw3Nyw2MywyMjMsMTAzLDEwOSw1NiwxNTgsNDMsMjA2LDIwMiwzOCwxNDgsMTM3LDE4OSwyMTQsMjE2LDkwLDE4LDIyNCwyNTQsMzcsMTA5LDE4LDg0LDIyMiwyMDksMjUsNTMsMjE5LDE2OSwyMTEsNTAsMTgyLDQwLDExMiwyMDksMzEsNTIsMjEsNTMsOTgsMTIyLDI1NCwxMDgsMzksMzgsMTM0LDE1MCwxMzksMTk0LDMw=")
Replace:
bytearray(ciphertext)
with:
bytearray(map(int, ciphertext.split(b',')))
# Or if you prefer genexprs:
bytearray(int(x) for x in ciphertext.split(b','))
The former is just converting the raw bytes to an equivalent bytearray, the latter splits it up by commas and parses the components as ints.
We are using below java code to decrypt the data which is encrypted using AES-256 in CBC mode and PKCS7 padding.
Java Code:
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import java.security.*;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
public class AES256 {
private static byte[] initVector = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
public String decrypt (String encryptedDataBase64, String keyBase64)
{
try {
Security.setProperty("crypto.policy", "unlimited");
IvParameterSpec ivSpec = new IvParameterSpec(initVector); // Get the init vector
// Get the Base64-encoded key
byte[] key = Base64.decodeBase64(keyBase64.getBytes("UTF-8"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); // AES / CBC / PKCS5 padding
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
byte[] encryptedData = Base64.decodeBase64(encryptedDataBase64.getBytes("UTF-8"));
byte[] decryptedData = cipher.doFinal(encryptedData);
return new String(decryptedData);
}
catch (Exception e) {
logger.error("AES256 Decrypt: Decryption exception: "+ e.getMessage());
return null;
}
}
}
Now we need to convert this decryption logic to Python as our app is sending the encrypted data in the headers while requesting for index.html from server. I tried to decrypt using Crypto. It is giving the decrypted string but also some additional characters in the end.
import base64
from Crypto.Cipher import AES
key = base64.b64decode(myKeyBase64)
enc = base64.b64decode(encDataBase64)
ivBase = base64.b64decode('AAAAAAAAAAAAAAAAAAAAAA==');
cipher = AES.new(key, AES.MODE_CBC, ivBase)
cipher.decrypt(enc).decode('utf-8')
It is decrypting properly but in the end it is giving some extra characters which are not in the original string like 'myText\x06\x06\x06\x06\x06\x06'.
I tried this after reading some of stack over flow questions. Can any one please let me know if there is any error in the code.
How to decode data encrypted using AES-256 in CBC mode and PKCS7 padding?
Encrypt & Decrypt using PyCrypto AES 256
To encrypt a byte array with AES you do need exactly a 16 byte long array - then you could use a '...NoPadding'.
Having e.g. a 13 character long string and you transform the string to a byte array this array is 13 bytes long. Using PKCS5 the byte array is filled up with 3 bytes of value x03. If you need to fill up 7 characters all 7 bytes will have the value x07, missing 10 chars result in 10 bytes of x0a.
To strip of the padding just read the last byte (e.g. x0a = '10') and remove the last 10 bytes to get the original string.
On Java-side the naming is PKCS5Padding that is (mostly) identical to PKCS7Padding (this naming is used in other frameworks/languages).
I'm trying to create an API with token to communicate between an Raspberry Pi and a Webserver. Right now i'm tring to generate an Token with Python.
from Crypto.Cipher import AES
import base64
import os
import time
import datetime
import requests
BLOCK_SIZE = 32
BLOCK_SZ = 14
#!/usr/bin/python
salt = "123456789123" # Zorg dat de salt altijd even lang is! (12 Chars)
iv = "1234567891234567" # Zorg dat de salt altijd even lang is! (16 Chars)
currentDate = time.strftime("%d%m%Y")
currentTime = time.strftime("%H%M")
PADDING = '{'
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
secret = salt + currentTime
cipher=AES.new(key=secret,mode=AES.MODE_CBC,IV=iv)
encode = currentDate
encoded = EncodeAES(cipher, encode)
print (encoded)
The problem is that the output of the script an exta b' adds to every encoded string.. And on every end a '
C:\Python36-32>python.exe encrypt.py
b'Qge6lbC+SulFgTk/7TZ0TKHUP0SFS8G+nd5un4iv9iI='
C:\Python36-32>python.exe encrypt.py
b'DTcotcaU98QkRxCzRR01hh4yqqyC92u4oAuf0bSrQZQ='
Hopefully someone can explain what went wrong.
FIXED!
I was able to fix it to decode it to utf-8 format.
sendtoken = encoded.decode('utf-8')
You are running Python 3.6, which uses Unicode (UTF-8) for string literals. I expect that the EncodeAES() function returns an ASCII string, which Python is indicating is a bytestring rather than a Unicode string by prepending the b to the string literal it prints.
You could strip the b out of the output post-Python, or you could print(str(encoded)), which should give you the same characters, since ASCII is valid UTF-8.
EDIT:
What you need to do is decode the bytestring into UTF-8, as mentioned in the answer and in a comment above. I was wrong about str() doing the conversion for you, you need to call decode('UTF-8') on the bytestring you wish to print. That converts the string into the internal UTF-8 representation, which then prints correctly.
I am trying to do the following:In a python script I use pycrypto lib to encrypt some text.Then I save it to file.Then I load that file and decode the encrypted text using the same key I used in Python.It fails at stfDecryptor.MessageEnd(); with the error:
"CryptoCPP::InvalidCiphertext at memory location [some memory]
Here is my code:
Python:
from Crypto.Cipher import AES
BLOCK_SIZE = 16
PADDING = '{'
# one-liner to sufficiently pad the text to be encrypted
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
EncodeAES = lambda c, s: c.encrypt(pad(s))
secret = 'MyKey123456789ab'
# create a cipher object using the random secret
cipher = AES.new(secret)
# encode a string
encoded = EncodeAES(cipher, textIn)
#save to file
fileOut = open("enc_shader.vert","w")
fileOut.write(encoded)
fileOut.close()
CPP :
std::string key = "MyKey123456789ab";
std::string iv = "aaaaaaaaaaaaaaaa";
std::ifstream fileIn("enc_shader.vert");
std::stringstream buffer;
buffer << fileIn.rdbuf();
std::string ciphertext1 = buffer.str();
CryptoPP::AES::Decryption aesDecryption((byte*)key.c_str(), CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, (byte*)iv.c_str() );
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decryptedtext ) );
stfDecryptor.Put( reinterpret_cast<const unsigned char*>( ciphertext1.c_str() ), ciphertext1.size() );
stfDecryptor.MessageEnd();//fails here.
From what I read these to endpoints should work as pycrypto just a wrapper for the CryptoCPP lib.May be I miss the padding on CPP side?
UPDATE:
Ok,I found that changing the padding scheme:
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decryptedtext ) ,BlockPaddingSchemeDef::NO_PADDING);
decodes the string on CPP side.But the decoded string contains the padding chars.
So if the original string was "aaaaaaaaaaaaaaaaa"
The decoded string looks like this:
"aaaaaaaaaaaaaaaaa{{{{{{{{{{{{{{{"
15 bytes were added to pad to 32 bytes.
Why Crypto++ doesn't remove those at decryption?
Your Python encryption code manually adds '{' characters to pad to the block size. This is not a defined padding mode, so the Crypto++ code will not be able to remove the padding using an integrated padding scheme. In other words, you should decrypt using NO_PADDING and then remove the padding yourself.
But it would be better to let the Python code use PKCS#7 padding, so you can use PKCS_PADDING as option within Crypto++.
I have just started using PyCrypto package for python.
I am trying out the following code under python 3.3.2:
Code Reference : AES Encryption using python
#!/usr/bin/env python
from Crypto.Cipher import AES
import base64
import os
# the block size for the cipher object; must be 16, 24, or 32 for AES
BLOCK_SIZE = 32
# the character used for padding--with a block cipher such as AES, the value
# you encrypt must be a multiple of BLOCK_SIZE in length. This character is
# used to ensure that your value is always a multiple of BLOCK_SIZE
PADDING = '{'
# one-liner to sufficiently pad the text to be encrypted
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
# one-liners to encrypt/encode and decrypt/decode a string
# encrypt with AES, encode with base64
EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
# generate a random secret key
secret = os.urandom(BLOCK_SIZE)
# create a cipher object using the random secret
cipher = AES.new(secret)
# encode a string
encoded = EncodeAES(cipher, 'password')
print ('Encrypted string:', encoded)
# decode the encoded string
decoded = DecodeAES(cipher, encoded)
print ('Decrypted string:', decoded)
The error that I run into is :
Traceback (most recent call last):
File "C:/Users/Hassan Javaid/Documents/Python files/crypto_example.py", line 34, in <module>
decoded = DecodeAES(cipher, encoded)
File "C:/Users/Hassan Javaid/Documents/Python files/crypto_example.py", line 21, in <lambda>
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
TypeError: Type str doesn't support the buffer API
Any pointers to why I am getting the same ?
This is because cipher.encrypt(plain_text) in python 3.x returns a byte string.
The example given in the page uses python 2.x in which case cipher.encrypt(plain_text) returned a regular string.
You can verify the same by using the type function:
In python 3.x:
>>> type(cipher.encrypt("ABCDEFGHIJKLMNOP"))
<class 'bytes'>
In python 2.x
>>> type(cipher.encrypt("ABCDEFGHIJKLMNOP"))
<class 'str'>
The error you are getting is because you are trying to use the rstrip method on a byte string.
Use:
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).decode("UTF-8").rstrip(PADDING)
This will decode the bytestring to regular string before using the rstrip method on it.
Another way to look at it is that the method rstrip accepts as argument a byte string if invoked on a byte string, or a regular string if invoked on a regular string.
Since decrypt of an AES object returns a byte string, DELIMITER should be defined as a byte string too:
PADDING = b'{'