TDEA and CBC mode? - encryption

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);
}

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?

GnuPG 1.4 RSA: Where's the Padding?

In an effort to better understand RSA I've been fooling around with the source code for GunPG 1.4, specifically the RSA implementation in the rsa.c file. As the title says, I can't figure out where the padding is happening.
So typically in RSA, padding is done right before the encryption and is taken off during the decryption. Encryption first starts around line 409 where we see
int
rsa_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
{
RSA_public_key pk;
if( algo != 1 && algo != 2 )
return G10ERR_PUBKEY_ALGO;
pk.n = pkey[0];
pk.e = pkey[1];
resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.n ) );
public( resarr[0], data, &pk );
return 0;
}
That seems easy, it's giving data to "public" function higher up on line 220. Public is responsible for calculating the important (c = m^e mod n) process. That all looks like:
static void
public(MPI output, MPI input, RSA_public_key *pkey )
{
if( output == input ) { /* powm doesn't like output and input the same */
MPI x = mpi_alloc( mpi_get_nlimbs(input)*2 );
mpi_powm( x, input, pkey->e, pkey->n );
mpi_set(output, x);
mpi_free(x);
}
else
mpi_powm( output, input, pkey->e, pkey->n );
}
Wait a second...now it looks like public is passing the job of that calculation off to mpi_powm() located in the mpi-pow.c file. I'll spare you the details but that function gets really long.
Somewhere in all of this some sort of PKCS#1 padding and unpadding (or something similar) is happening but I can't figure out where for the life of me. Can anyone help me see where the padding happens?
In an effort to better understand RSA I've been fooling around with the source code for GnuPG 1.4, specifically the RSA implementation in the rsa.c file.
Since you’re looking at the older (< 2.0) stuff anyway, and since it’s only for learning purposes, I would rather advise you to check out “ye olde rsaref.c from gnupg.org” where the padding is implemented in a pretty obvious way.
… some sort of PKCS#1…
To be exact, GnuPG uses PKCS #1 v1.5 (specified in RFC 4880).
Can anyone help me see where the padding happens?
Hmmm, let’s see if I can wrap that up somewhat logically. GnuGP pads according to PKCS #1 v1.5, so it just adds random pad to satisfy length requirements.
If you take a look at the cipher/pubkey.c file (which includes the rsa.h file in its head), you’ll notice a pubkey_table_s struct which defines a list of elements that define the key. For padding reasons, random bytes are appended to that list (better: after that struct). It’s done that way because those random bytes can easily be stripped by looking for the end of the list. Keeping a long story short, that’s where random.c probably starts to make a bit more sense to you. Now, all that stuff (and a whole lot more) is compiled into a lib called libcipher… which in itself is compiled to be used by functions that add the padding and handle the RSA stuff the way you expected it. In the end, the compiled executables use the functions libcipher provides to take care of the padding – depending on the individual need for padding.
So what you currently expect to find in 1 or 2, maybe 3 files is actually spread out across more than half a dozen files… which I regard not to be the best base for your learning efforts. As said, for reference purposes, I’ld go for the old rsaref.c they once started out with.
Not sure if this actually provides all the details you wanted to get, but it should give you a first good heads-up… hope it helps.
GPG 1.4 doesn't use any padding at all. It encrypts the raw session key.

Is my PyCrypto implementation secure for my purposes?

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.

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.

Resources