I've a django app which serves encrypted media files to Flash apps. Encryption in python is done with PyCrypto as follows (I include description too in case useful):
def encrypt_aes(key, text):
try:
raw = _pad(text)
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw))
except Exception as e:
print e.message
return text
def decrypt_aes(key, text):
try:
enc = base64.b64decode(text)
iv = enc[:AES.block_size]
cipher = AES.new(key, AES.MODE_CBC, iv)
return _unpad(cipher.decrypt(enc[AES.block_size:]))
except Exception as e:
print e.message
return text
def _pad(s):
bs = 16
return s + (bs - len(s) % bs) * chr(bs - len(s) % bs)
def _unpad(s):
return s[:-ord(s[len(s) - 1:])]
I cannot yet decrypt the Python provided media files (downloaded with LoaderMax by GreenSock, using 'DataLoader'). My AS3 code (using AS3Crypto) is as follows:
public static function decipher(_key:String):void{
key=_key;
cipher = Crypto.getCipher("simple-aes-cbc", Hex.toArray(key));
cipher.decrypt(ByteArray(_content));
}
I get
RangeError: Error #2006
One suspicion is that in Python I have 64bit base but I think that AS3 ByteArray is 32bit base. I have tried the below, but get the same Error.
cipher.decrypt(ByteArray(com.hurlant.util.Base64.decodeToByteArray(_content)));
Another suspicion is that I have not appropriately removed 'padding' from the _content / set up my IV appropriately (which is specified by the padding I must remove from the _content). This should be done via that "simple" statement however. I have been trying this, but with no success:
var pad:IPad = new PKCS5
cipher = Crypto.getCipher("simple-aes", Hex.toArray(key),pad);
pad.setBlockSize(cipher.getBlockSize());
Could anyone advise on how I can fix this ? :)
Many thanks!
OK finally figured out what was going wrong. Besides some AS3 tweaks, we wrongly were transmitting files as MP3/image (should have been text/html).
Our Python remains as above. Our AS3 is tweaked to the below.
Here's the AS3 class we used:
package com.xperiment.preloader
{
import com.greensock.loading.DataLoader;
import com.hurlant.crypto.Crypto;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.util.Base64;
import flash.events.Event;
import flash.utils.ByteArray;
public class EncryptedDataLoader extends DataLoader
{
private static var backlog:Vector.<EncryptedDataLoader>;
private static var cipher:ICipher;
private var decrypted:Boolean = true;
public function EncryptedDataLoader(urlOrRequest:*, vars:Object=null)
{
this.addEventListener(Event.COMPLETE,decryptL);
super(urlOrRequest, vars);
}
public function decryptL(e:Event):void {
trace("start decrypt");
e.stopImmediatePropagation();
this.removeEventListener(Event.COMPLETE,decryptL);
backlog ||= new Vector.<EncryptedDataLoader>;
backlog.push(this);
if(cipher) pingBacklog();
}
public function decipher():void
{
_content = Base64.decodeToByteArray( _content );
cipher.decrypt( _content );
decrypted=true;
this.dispatchEvent(new Event(Event.COMPLETE));
}
public static function setCipher(_key:String):void{
var keyBA:ByteArray = new ByteArray;
keyBA.writeMultiByte(_key, "iso-8859-1");
cipher = Crypto.getCipher("simple-aes", keyBA);
pingBacklog();
}
public static function kill():void{
cipher.dispose();
cipher = null;
}
public static function pingBacklog():void{
if(backlog){
var encrypted:EncryptedDataLoader;
while(backlog.length>0){
encrypted=backlog.shift();
encrypted.decipher();
}
backlog=null;
}
}
}
}
Related
I'm trying to sign message with RSA in Python and then verifying data in C#, but getting fail still after hours of testing/fighting.
Python code for signing:
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization
message = b"Test string"
with open("id_rsa", "rb") as key_file:
private_key = serialization.load_pem_private_key(
key_file.read(),
password=None,
)
signature = private_key.sign(
message,
padding.PKCS1v15(),
hashes.SHA256()
)
signaturefile = open('signed.dat', 'wb')
signaturefile.write(signature)
signaturefile.close()
datafile = open('message.dat', 'wb')
datafile.write(message)
datafile.close()
And C# code for verifying:
private void button_Click(object sender, EventArgs e)
{
byte[] data = File.ReadAllBytes("message.dat");
byte[] signature = File.ReadAllBytes("signed.dat");
try
{
using (var reader = File.OpenText("id_rsa.pub"))
{
var pem = new PemReader(reader);
var o = (RsaKeyParameters)pem.ReadObject();
using (var rsa = new RSACryptoServiceProvider())
{
var parameters = new RSAParameters();
parameters.Modulus = o.Modulus.ToByteArray();
parameters.Exponent = o.Exponent.ToByteArray();
rsa.ImportParameters(parameters);
bool ok = rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
if (ok) Console.WriteLine("Verified");
}
}
}
catch (CryptographicException exc)
{
Console.WriteLine(exc.Message);
}
}
I'm getting always fail from rsa.VerifyData. Could someone point me what is the problem?
Same files can be verified well in Python.
RSAParameters#Modulus and RSAParameters#Exponent expect modulus and exponent unsigned, so Org.BouncyCastle.Math.BigInteger#ToByteArrayUnsigned() must be used instead of Org.BouncyCastle.Math.BigInteger#ToByteArray(). With this change, verification is successful.
Also, the big endian byte order is required, but this applies to both methods.
Note that System.Numerics.BigInteger#ToByteArray() returns the data signed with little endian order.
Your current approach uses BC for key import and built-in .NET methods for verification. Alternatively, BC classes can also be used for verification, making for a slightly more efficient implementation overall.
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
...
ISigner signer = SignerUtilities.GetSigner("SHA256withRSA");
signer.Init(false, o);
signer.BlockUpdate(data, 0, data.Length);
bool verified = signer.VerifySignature(signature);
I have this encrypt with AES function in python:
def encrypt_text(self):
raw = self.PKCS7_padding()
iv = Random.new().read(self.block_size)
cipher = AES.new(self.key, AES.MODE_CBC, iv)
encrypted = base64.b64encode(iv + cipher.encrypt(raw))
return encrypted
And then padding it with:
def PKCS7_padding(self):
return self.text+chr(16-len(self.text)%16)*(16-len(self.text)%16)
But when I send it to this c# function
public static string DecryptString(string key, string cipherText)
{
byte[] iv = new byte[16];
byte[] buffer = Convert.FromBase64String(cipherText);
using (Aes aes = Aes.Create())
{
aes.Key = Convert.FromBase64String(key);
aes.IV = iv;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream(buffer))
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
{
using (StreamReader streamReader = new StreamReader((Stream)cryptoStream))
{
return streamReader.ReadToEnd();
}
}
}
}
}
Say i send "hello world"
I get a weird mix of the string i sent plus random non pritable characters. EX: "�Ȯ�Ŗf�"��Xhello world"
The key is generated as follows:
key = base64.b64encode(os.urandom(32))
return key.decode()
I do not get any errors but weird text any ideas Thanks! If you have any questions please feel free to ask
In the Python code, a random IV is generated and concatenated with the ciphertext. However, in the C# code, the separation of IV and ciphertext is missing. Instead, a zero IV is applied and the concatenation of IV and ciphertext is decrypted, which causes the problem.
The separation of IV and ciphertext can be added to the C# code e.g. as follows:
byte[] buffer = ...
byte[] ct = new byte[buffer.Length - iv.Length];
Buffer.BlockCopy(buffer, 0, iv, 0, iv.Length);
Buffer.BlockCopy(buffer, iv.Length, ct, 0, ct.Length);
buffer = ct;
using ...
Note that PyCryptodome supports padding in a dedicated module: Crypto.Util.Padding.
Also, in the Python code the Base64 encoded key is nowhere Base64 decoded (but maybe the corresponding code was just not posted).
I have some already encrypted data which needs to be decrypted using python. The decryption logic in C# looks as given below.
using System.Security.Cryptography;
private const string Url_ENCRYPTION_KEY = "abcd123456";
private readonly static byte[] URL_SALT = Encoding.ASCII.GetBytes(Url_ENCRYPTION_KEY.Length.ToString());
public static string Decrypt(string inputText) {
try {
if (!string.IsNullOrEmpty(inputText)) {
RijndaelManaged rijndaelCipher = new RijndaelManaged();
byte[] encryptedData = Convert.FromBase64String(inputText.Replace(" ", "+"));
PasswordDeriveBytes secretKey = new PasswordDeriveBytes(Url_ENCRYPTION_KEY, URL_SALT);
using (ICryptoTransform decryptor =
rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16))) {
using (MemoryStream memoryStream = new MemoryStream(encryptedData)) {
using (CryptoStream cryptoStream =
new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) {
byte[] plainText = new byte[encryptedData.Length];
int decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);
return Encoding.Unicode.GetString(plainText, 0, decryptedCount);
}
}
}
}
}
catch(Exception ex) {
//clsErrorHandler.LogError(ex);
}
return inputText;
}
I have tried libs like pprp and python's cryptography but the solutions out there use PBKDF2, while the C# code here supplies the decryptor bytes of key and salt as key and IV values.
From what I looked the PasswordDeriveBytes function basically work as a somewhat modified PBKDF1,
but all of the solutions I tried fail with somekind of esoteric this size doesn't match with that size errors.
Here is one implementation of PasswordDeriveBytes I found floating out there but I am at a loss on how to do something similar to secretKey.GetBytes(32) and creating a decryptor
import hashlib
from base64 import b64decode
def MS_PasswordDeriveBytes(pstring, salt, hashfunc, iterations, keylen):
if iterations > 0:
lasthash = hashlib.sha1(pstring+salt).digest()
iterations -= 1
else:
print("Iterations must be > 0")
#If iterations is 1 then basically the same thing happens as 2 based on my testing
#if iterations == 0 and keylen > len(lasthash):
#print("Dunno what happens here")
#return -1
for i in range(iterations-1):
lasthash = hashlib.sha1(lasthash)
bytes = hashlib.sha1(lasthash).digest()
ctrl = 1
while len(bytes) < keylen:
bytes += hashlib.sha1(str(ctrl)+lasthash).digest()
ctrl += 1
return(bytes[:keylen])
stpass = 'amp4Z0wpKzJ5Cg0GDT5sJD0sMw0IDAsaGQ1Afik6NwXr6rrSEQE='
slt = 'aGQ1Afik6NampDT5sJEQE4Z0wpsMw0IDAD06rrSswXrKzJ5Cg0G='
initv = '#1B2c3D4e5F6g7H8'
enc_str = b64decode('B5YDTLEDBjd+8zy5lzEfjw==')
derbytes = MS_PasswordDeriveBytes(stpass, slt, hashlib.sha1, iterations=2, keylen=32)
I'm struggling to encode a string to SHA-256 with a specific key.
There is a python code that is used a reference.
The problem is that I cannot achieve the same result in C#.
import base64
import hmac
import hashlib
# Base64 encoded key (get it with /hook/{hookId}/key request)
webhook_key_base64 = 'JcyVhjHCvHQwufz+IHXolyqHgEc5MoayBfParl6Guoc='
# notification parameters
data = '643|1|IN|+79165238345|13353941550'
webhook_key = base64.b64decode(s))
print(hmac.new(webhook_key, data.encode('utf-8'), hashlib.sha256).hexdigest())
C#
public class Program
{
public static void Main()
{
var key = "JcyVhjHCvHQwufz+IHXolyqHgEc5MoayBfParl6Guoc=";
var message = "643|1|IN|+79165238345|13353941550";
var decodedKey = Base64Decode(key);
var result = HmacSha256Digest(message, decodedKey);
Console.WriteLine(result);
Console.ReadLine();
}
private static string HmacSha256Digest(string message, string secret)
{
var keyBytes = Encoding.UTF8.GetBytes(secret);
var messageBytes = Encoding.UTF8.GetBytes(message);
var cryptographer = new HMACSHA256(keyBytes);
var bytes = cryptographer.ComputeHash(messageBytes);
return BitConverter.ToString(bytes).Replace("-", "").ToLower();
}
private static string Base64Decode(string base64EncodedData)
{
var base64EncodedBytes = Convert.FromBase64String(base64EncodedData);
return Encoding.UTF8.GetString(base64EncodedBytes);
}
}
What could be wrong?
Thanks
I am adding a go application to an already existing python codebase. I've been having trouble dealing with encryption between the languages. This is using go 1.2.1 and Python 2.7.x / PyCrypto 2.7a1.
Here is the Python sample:
import Crypto.Cipher
import Crypto.Hash.HMAC
import Crypto.Hash.SHA256
import Crypto.PublicKey.RSA
from binascii import hexlify, unhexlify
#encrypt
payload = unhexlify("abababababababababababababababababababababababababababababababab")
password = unhexlify("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")
iv = unhexlify("00000000000000000000000000000000")
print "IV: ", hexlify(iv), "len: ", len(iv)
print "Password length: ", len(password)
cipher = Crypto.Cipher.AES.new(
key=password,
mode=Crypto.Cipher.AES.MODE_CFB,
IV=iv)
payload = cipher.encrypt(payload)
print hexlify(payload) #dbf6b1877ba903330cb9cf0c4f530d40bf77fe2bf505820e993741c7f698ad6b
And this is the Go sample:
package main
import (
"fmt"
"crypto/cipher"
"crypto/aes"
"encoding/hex"
)
// encrypt
func main() {
payload, err1 := hex.DecodeString("abababababababababababababababababababababababababababababababab")
password, err2 := hex.DecodeString("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")
iv, err3 := hex.DecodeString("00000000000000000000000000000000")
if err1 != nil {
fmt.Printf("error 1: %v", err1)
return
}
if err2 != nil {
fmt.Printf("error 2: %v", err2)
return
}
if err3 != nil {
fmt.Printf("error 3: %v", err3)
return
}
aesBlock, err4 := aes.NewCipher(password)
fmt.Printf("IV length:%v\n", len(iv))
fmt.Printf("password length:%v\n", len(password))
if err4 != nil {
fmt.Printf("error 4: %v", err4)
return
}
cfbDecrypter := cipher.NewCFBEncrypter(aesBlock, iv)
cfbDecrypter.XORKeyStream(payload, payload)
fmt.Printf("%v\n", hex.EncodeToString(payload)) // db70cd9e6904359cb848410bfa38d7d0a47b594f7eff72d547d3772c9d4f5dbe
}
Here is the golang link, I could not find a Python pastebin that had PyCrypto installed.
As suggested by the title & source, the two snippets produce different cyphertext:
Python: dbf6b1877ba903330cb9cf0c4f530d40bf77fe2bf505820e993741c7f698ad6b
Golang: db70cd9e6904359cb848410bfa38d7d0a47b594f7eff72d547d3772c9d4f5dbe
Both languages can decrypt their 'native' cypthertext, but neither can decrypt the others'. Because the python implementation already exists, I'm looking for a solution that will allow Go to decrypt cyphertext encrypted with the example PyCrypto AES settings & key size.
Research on the current system has revealed that our python system uses CFB8 (8 bit segments). Go does not support this out of the box, but the source code used in the current CFBDecrypter / CFBEncrypter looks like it can be adapted fairly easily.
If anyone is looking for Go implementation of CFB mode with segment size = 8 you can use this:
import "crypto/cipher"
// CFB stream with 8 bit segment size
// See http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
type cfb8 struct {
b cipher.Block
blockSize int
in []byte
out []byte
decrypt bool
}
func (x *cfb8) XORKeyStream(dst, src []byte) {
for i := range src {
x.b.Encrypt(x.out, x.in)
copy(x.in[:x.blockSize-1], x.in[1:])
if x.decrypt {
x.in[x.blockSize-1] = src[i]
}
dst[i] = src[i] ^ x.out[0]
if !x.decrypt {
x.in[x.blockSize-1] = dst[i]
}
}
}
// NewCFB8Encrypter returns a Stream which encrypts with cipher feedback mode
// (segment size = 8), using the given Block. The iv must be the same length as
// the Block's block size.
func newCFB8Encrypter(block cipher.Block, iv []byte) cipher.Stream {
return newCFB8(block, iv, false)
}
// NewCFB8Decrypter returns a Stream which decrypts with cipher feedback mode
// (segment size = 8), using the given Block. The iv must be the same length as
// the Block's block size.
func newCFB8Decrypter(block cipher.Block, iv []byte) cipher.Stream {
return newCFB8(block, iv, true)
}
func newCFB8(block cipher.Block, iv []byte, decrypt bool) cipher.Stream {
blockSize := block.BlockSize()
if len(iv) != blockSize {
// stack trace will indicate whether it was de or encryption
panic("cipher.newCFB: IV length must equal block size")
}
x := &cfb8{
b: block,
blockSize: blockSize,
out: make([]byte, blockSize),
in: make([]byte, blockSize),
decrypt: decrypt,
}
copy(x.in, iv)
return x
}
It seems that the cipher can be made compatible to Go's crypto/cipher if we change segment_size of AES object from the default 8 to AES.block_size*8 (which is 128), like this:
Crypto.Cipher.AES.new(
key=password,
mode=Crypto.Cipher.AES.MODE_CFB,
IV=iv,
segment_size=AES.block_size*8
)
I found that easiest way to deal with this from Python side is to use M2Crypto library.
Final code looks like:
import M2Crypto.EVP
iv = ciphertext[:16]
ciphertext = ciphertext[16:]
cipher = M2Crypto.EVP.Cipher('aes_256_cfb', t, iv, 0)
text = cipher.update(ciphertext)
print text
Works perfect without need to change something in Go.
i solve by adapt python code like this (golang encode and python decode):
# golang encode
padNum := len(data) % 16
if padNum != 0 {
for i := 0; i < 16-padNum; i++ {
data = append(data, ',')
}
}
# python decode
cipher = AES.new(key=self.key, mode=AES.MODE_CFB, IV=iv,segment_size=128)