Is my PyCrypto implementation secure for my purposes? - encryption

I'm not experienced with programming, and the PyCrypto documentation is pretty sparse for a beginner. Let's say that I encrypt a file with the code I have written below, and send it over the internet. What I'm concerned about is the security of the file between computers A and B. Let's assume that the computers themselves are secure and the key is transported securely. Have I implemented things correctly? Anything else I should know about? Using Python 2.7 and PyCrypto 2.6
Thank you in advance for any answer.
from Crypto.Cipher import AES
from Crypto import Random
def get_random(length):
r = Random.new().read(length)
return r
def aes_encrypt(key, file_in, file_out):
data_source = open(file_in, 'rb')
data = data_source.read()
data_source.close()
iv = get_random(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
data_encrypted = iv+cipher.encrypt(data)
file_encrypted = open(file_out, 'wb')
file_encrypted.write(data_encrypted)
file_encrypted.close()
def aes_decrypt(key, file_in, file_out):
data_source = open(file_in, 'rb')
data = data_source.read()
data_source.close()
iv = data[:AES.block_size]
data = data[AES.block_size:]
cipher = AES.new(key, AES.MODE_CFB, iv)
data_decrypted = cipher.decrypt(data)
file_decrypted = open(file_out, 'wb')
file_decrypted.write(data_decrypted)
file_decrypted.close()
#testing
key = get_random(32)
#encrypting the file on computer A
aes_encrypt(key, 'file.dat', 'file.enc')
#decrypting the file on computer B
aes_decrypt(key, 'file.enc', 'file.dat')

You are missing one of the most important considerations in implementing crypto, which is message integrity. Unfortunately just encrypting a message isn't enough to ensure it isn't tampered with, especially in the case of streaming modes like CTR, CFB, and OFB.
It looks like you are using CFB mode (MODE_CFB). The way this works is a random keystream is generated with AES, and the result is XOR-ed against the plaintext. This means that if someone flips a bit in the ciphertext, the corresponding bit will flip in the decrypted plaintext. An attacker could alter your message to mean something entirely different, and there'd be no way for you to detect it. For reference of how CFB mode (decryption) works:
If I flip the first bit of the first block of the ciphertext, it'll flip the first bit of the first block of the decrypted plaintext.
You need to either apply an HMAC or use AES-GCM mode, which will handle confidentiality and integrity together.
There are better mode choices than CFB, so if there's no strong reason for preferring it, I would recommend AES-GCM first, then AES-CTR with HMAC second.

Related

Erlang crypto:stream_init gives different keys on 32 & 64 bit systems. How to use?

I'm getting different keys when using crypto:stream_init(rc4, String). on 32 bit erlang vs 64 bit erlang.
I need to use crypto:stream_encrypt() on one and crypto:stream_decrypt() on the other. Any way to get this to work?
Thanks
crypto:stream_init() returns a State, not a key, and its binary representation will look different on 32 vs 64 bit architectures.
The encrypt/decrypt operations will still work the same, as they rely on the underlying OpenSSL implementation.
As an example of encryption:
State = crypto:stream_init(rc4, "SecretKey").
{Newstate, Secret} = crypto:stream_encrypt(State, "SecretMessage").
And decryption:
State = crypto:stream_init(rc4, "SecretKey"),
{Newstate, Message} = crypto:stream_decrypt(State, Secret),
Message = "SecretMessage".
i.e. the decrypt operation should return the same SecretMessage that was encrypted using the key SecretKey.

Getting mac from HMAC value and key

I am looking at this page on how to validate HMAC implementation on a platform: http://csrc.nist.gov/groups/STM/cavp/
Test Vectors:
HMAC Test Vectors - These files provide an electronic version of the test vectors
that can be used to informally verify the correctness of an HMAC algorithm
implementation using the HMACVS. However, use of these vectors does not
take the place of validation obtained through the Cryptographic Algorithm
Validation Program (CAVP).
So I open up the file and view the test values:
http://pastebin.com/phJ4C0Fx
it is thousands of lines long but this is the start.
I focus on the first values:
[L=20]
Count = 0
Klen = 10
Tlen = 10
Key = 82f3b69a1bff4de15c33
Msg = fcd6d98bef45ed6850806e96f255fa0c8114b72873abe8f43c10bea7c1df706f10458e6d4e1c9201f057b8492fa10fe4b541d0fc9d41ef839acff1bc76e3fdfebf2235b5bd0347a9a6303e83152f9f8db941b1b94a8a1ce5c273b55dc94d99a171377969234134e7dad1ab4c8e46d18df4dc016764cf95a11ac4b491a2646be1
Mac = 1ba0e66cf72efc349207
My understanding is that with a key and value that openssl would get the mac, however I am not getting the same mac as that above?
echo -n "<Msg here>" | openssl sha1 -hmac "82f3b69a1bff4de15c33"
(stdin)= 981c64f70b07634e01b3800447e6431dddb42530
Any ideas on what I am doing wrong? i am also just guessing sha1, other values don't match either, I don't know how to take from the file what way I should be doing this. The various lengths, and the count. How do I use this information?

Scapy raw data manipulation

I am having troubles manipulating raw data. I am trying to change around a
resp_cookie in my ISAKMP header and when I do a sniff on the packet it is all in raw data format under Raw Load='\x00\x43\x01........... ' with about 3 lines like that. When I do a Wireshark capture I see the information I want to change but I cant seem to find a way to convert and change that raw data to find and replace the information I am looking for. Also, I can see the information I need when I do a hexdump(), but I can't store that in a variable. when I type i = hexdump(pkt) it spits out the hexdump but doesn't store the hexdump in i.
So this post is a little old, but I've come across it a dozen or so times trying to find the answer to a similar problem I'm having. I doubt OP has need for an answer anymore, but if anyone else is looking to do something similar...here you go!
I found the following code snippet somewhere in the deep, dark depths of google and it worked for my situation.
Hexdump(), show() and other methods of Scapy just output the packet to the terminal/console; they don't actually return a string or any other sort of object. So you need a way to intercept that data that it intends to write and put it in a variable to be manipulated.
NOTE: THIS IS PYTHON 3.X and SCAPY 3K
import io
import scapy
#generic scapy sniff
sniff(iface=interface,prn=parsePacket, filter=filter)
With the above sniff method, you're going to want to do the following.
def parsePacket(packet):
outputPacket = ''
#setup
qsave = sys.stdout
q = io.StringIO()
#CAPTURES OUTPUT
sys.stdout = q
#Text you're capturing
packet.show()
#restore original stdout
sys.stdout = qsave
#release output
sout = q.getvalue()
#Add to string (format if need be)
outputPacket += sout + '\n'
#Close IOStream
q.close()
#return your packet
return outputPacket
The string you return (outputPacket) can now be manipulated how you want.
Swap out .show() with whatever function you see fit.
P.S. Forgive me if this is a little rough from a Pythonic point of view...not a python dev by any stretch.

CF DESEDE encrypt() Key Length Issue

I am trying to encrypt a string using ColdFusion encrypt() with a 3rd party provided key like this:
encrypteded = encrypt('theString', 'FD52250E230D1CDFD5C2DF0D57E3E0FEFD52250E230D1CDF', 'DESEDE/CBC/NoPadding', 'BASE64', ToBase64('0'));
I get:
"The key specified is not a valid key for this encryption: Wrong key algorithm, expected DESede."
What do I have to do to this key in terms of encoding/decoding to get it into the right format?
Generally, when using provided keys from other languages, you have to do a little gymnastics on it to get it into Base64.
Try this for the key argument:
ToBase64(BinaryDecode('FD52250E230D1CDFD5C2DF0D57E3E0FEFD52250E230D1CDF','hex'))
But, to make this work for me, the input string needed to be a multiple of 8 bytes (because you're specifying NoPadding), and the IV needed to also be a multiple of 8 bytes.
So, this ended up working for me - not sure if you'll be able to decrypt it on the other end, tho, if the IV they're specifying is really what you've got listed there.
encrypteded = encrypt('theStrin', ToBase64(BinaryDecode('FD52250E230D1CDFD5C2DF0D57E3E0FEFD52250E230D1CDF','hex')), 'DESEDE/CBC/NoPadding', 'BASE64', ToBase64('0000'));
No IV also worked as well (with different output, obviously):
encrypteded = encrypt('theStrin', ToBase64(BinaryDecode('FD52250E230D1CDFD5C2DF0D57E3E0FEFD52250E230D1CDF','hex')), 'DESEDE/CBC/NoPadding', 'BASE64');
If you've been given a Hex IV, then you can use it as such:
encrypteded = encrypt('theStrin', ToBase64(BinaryDecode('FD52250E230D1CDFD5C2DF0D57E3E0FEFD52250E230D1CDF','hex')), 'DESEDE/CBC/NoPadding', 'BASE64', BinaryDecode("7fe8585328e9ac7b","hex"));
Hopefully this is enough info to get you on your way!
The only thing that seems off to me is the algorithm value you're using. Maybe try this?
encrypteded = encrypt('theString', 'FD52250E230D1CDFD5C2DF0D57E3E0FEFD52250E230D1CDF', 'DESEDE', 'BASE64', ToBase64('0'));
I don't know if the /CBC/NoPadding settings will be what you want, but I don't think they will be allowed in the algorithm argument.

TDEA and CBC mode?

I am trying to get the hang of encryption diagrams and TDEA (Triple DES). I understand TDEA looks something like this:
ciphertext = EK3(DK2(EK1(plaintext)))
I also know a chain block cipher uses an IV to seed the encryption and the plain text before encrypting, and then the output is a block that is ciphered and the new IV is formed from the output of the first block's cipher text. Correct?
This means a TDEA in CBC mode would flow something like this:
Plain Text --> IV --> TDEA encryption --> NEW IV --> Cipher Text
The next block is:
Plain Text --> NEW IV --> TDEA encryption --> NEW NEW IV --> Cipher Text
This continues on for n number of blocks. Is this correct or am I not getting how it works?
Your conception of how CBC works seems to be flawed (or at least I don't understand how you're saying you believe things work). In particular, you're showing Plain Text -> IV, but the IV does not depend (in any way) on the plain text.
The cipher algorithm you use is basically orthogonal to how CBC itself works (beyond the fact that it's for block ciphers, not stream ciphers). In pseudo-code, CBC looks something like this:
block_t xor_block = IV;
write(xor_block);
for (int i=0; i<message_size; i++) {
block_t data = xor(xor_block, message[i]);
xor_block = encrypt(data);
write(xor_block);
}

Resources