How to create symmetric encryption key with Google Tink? - cryptography

I have a key (say) "thisist0psecret" that I want to use as a symmetric encryption/decryption key with the Google Tink library. I am baffled that I am unable to do this simple thing. I can generate new keys (using various templates AES128_GCM, etc.), serialize them and then read them back with KeysetReader. But, for the life of me, I cannot figure out how to create a symmetric key with the specific key bytes that I specify.
I am able to do the following, for example, with Tink:
KeysetHandle ksh = KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM);
Aead aead = AeadFactory.getPrimitive(ksh);
String pt = "hello, world!";
byte[] encbytes = aead.encrypt(pt.getBytes(), null);
byte[] decbytes = aead.decrypt(encbytes, null);
String orig = new String(decbytes);
assert(pt.equals(orig));
But I want to set the symmetric key string to be a set of bytes that I specify such as "thisist0psecret" and then encrypt this key with the public key of the user who will do the decryption.
Any Google Tink experts here that can shed some light?

I'm the lead developer for Tink.
If your key is randomly generated, you can use the subtle API directly, see: https://github.com/google/tink/blob/master/java_src/src/main/java/com/google/crypto/tink/subtle/AesGcmJce.java.
This is not recommended because the subtle layer might change without notice (thought it's been relatively stable in the history of Tink).
If your key is a password you want to derive a key from it using something like Scrypt or PBKDF2. We haven't yet support native password-based encryption in Tink, please file a feature request and we'll see how we can help.

Related

storing password in source

I have read several places now which basically advise against storing a password in source code, and I understand the reasons.
I have two apps: one for encryption and one for decryption. Data is encrypted to a file on a server; this file is downloaded and decrypted on a client's machine, and then processed by a proprietary app (not mine). The data is sensitive and, (ideally) is meant to be only accessible to the processing app.
As it stands I am using a symmetric key algorithm since the data is large enough. The password is hardcoded into the source code as a string - I know, bad for several reasons.
What I would like to know is what's the best way to store the password? My thought is to use an asymmetric key algorithm e.g. RSA, just for the password, but can't wrap my head around how to do this and if it even makes sense in my scenario. I'd prefer not introduce another file for distribution. I don't know much about decompiling, but I figured implementing a PBKD into the client app would pose the same problem. Cryptography is new to me as you can tell, and using this great forum.
Please don't use symmetrical keys in source files. You can use RSA without introducing another file. As opposed to symmetrical keys, the public key can be hard-coded in source code without any security issues, iff you can guarantee the integrity of the source file. Then again, if someone manages to change it, decryption won't work or there is a man-in-the-middle (MITM) attack going on (and you wouldn't know about it).
CAVEATS
This approach suffers from susceptibility of a MITM attack. An appropriate countermeasure would be to sign the data, but then you are stuck handling the keys and is really a separate question.
Keys are not forever, the key-pair you generate needs to be rotated from time to time.
Make the keys big enough (at least 2048 bits).
Revocation needs to be done manually by you. If you need a more automated solution, consider looking at PKI and OSCP Responders (with or without stapling).
If the data you are sending is large, RSA operations will be lengthy.
Ok, with that out of the way, let's dig in. The example code is written entirely with JDK 8.
First, generate a key-pair. This needs to be done once or every time you need to rotate:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
KeyPair keyPair = kpg.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
byte[] pubEnc = publicKey.getEncoded();
byte[] privKeyEnc = privateKey.getEncoded();
System.out.println(Base64.getEncoder().encodeToString(pubEnc));
System.out.println(Base64.getEncoder().encodeToString(privKeyEnc));
Let's say the public key was (these are actual keys I generated, don't use these):
private static final String PUBLIC_KEY_BASE64 =
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCGue
5TCdPJt08w7crbvWjfcSUy/xXjzjjjjPDP7D8PNSnn
CUeNcGWsR/Pd3eoBjmrAy/4Rl8JlHylRry8pX7Zpcz
iQB8wWQdpkSoArjeu4taeFn/45+eg4J5mzmIzFG9F5
wF7N+SeSvtq3E3Q0mtJRRZZJYgNkFmeDuOQjljJVZw
IDAQAB";
and the private key was:
private static final String PRIVATE_KEY_BASE64 =
"MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAg
EAAoGBAIa57lMJ08m3TzDtytu9aN9xJTL/FePOOOOM
8M/sPw81KecJR41wZaxH893d6gGOasDL/hGXwmUfKV
GvLylftmlzOJAHzBZB2mRKgCuN67i1p4Wf/jn56Dgn
mbOYjMUb0XnAXs35J5K+2rcTdDSa0lFFlkliA2QWZ4
O45COWMlVnAgMBAAECgYBAWTIRi1ISuHEkh48qoS8j
+eCwmNGVuvvFA55JUSdVVikrZm08iwCk5sD9qW6JS8
KFT2mMcZWxws5za171PffbeHoIFaNI5n5OXJa4meZA
cgl4ae5su89BjvfzDF2gsnBHwLpgsT0aVdIDQ5BGtL
WzRwZCogY6lZhBOQZAaNFYIQJBALr2+kT+pkSlxrrR
tMxK7WL+hNO7qOIl/CTBuAa6/zTtoEjFMFQBY//jH+
6iabHDfKpaFwh6ynZTXZsb7qIKOM8CQQC4eRAH1VEo
iofZNnX3VjiI5mLtV8rc8Jg+wznN+WFnwdNoLK8y9t
EcuKxg3neIJAM70D6l0IhBfza1QAqQh4/pAkA5vyLZ
wJV2SoWxGihvmQztMJOyGho1j2nrqHHAkm1U2bhSAa
XFrJBIbsxkFoHyx+BvdVf75IE4PtOAnwX7wpB9AkBQ
7CKBHS2N+D8hpQdYqcUBIPdyoFmIVC6lEaTw2x3Ekz
027KsqUyVmUQilMdIDsbCNc4uX14N+H90S43X+8sjJ
AkAKsvRbZ0Au9JytSRKSB7vYl37283zHoQ5jyYUE7x
g7C6nWSl1GEa6khZ47hFAj9C2bdLJ6GtjTleFsVCsR
LUoG";
The keys above are line wrapped for formatting reasons.
Let's say args[0] was "attack at dawn!" and you client looks like this:
public static void main(String[] args) throws Exception {
byte[] pubKey = Base64.getDecoder().decode(PUBLIC_KEY_BASE64);
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(pubKey));
Cipher cipher = Cipher.getInstance("RSA");
Cipher.init(Cipher.ENCRYPT_MODE, publicKey);
String encryptedData = Base64.getEncoder().encodeToString(cipher.doFinal(args[0].getBytes("UTF-8")));
System.out.println("Encrypted data is: " + encryptedData);
}
Output: Encrypted data is:
cDoPpQYc6qibrBl5jdENcV+g6HslQDlo9potca5rQxecnxR3Bd/e1T0njqUMACl7x7AG3foGxqZyyUIMrOVXcnw/ux7BgQcg+RDZhSVFQAd5kUGI96pw8WtDVo1N1+WEfaaPhK9CpwUKUxtwR0t27n+W0vhFCqNTEGhofLt8u9o=
The server:
public static void main(String[] args) throws Exception {
byte[] privKey = Base64.getDecoder().decode(PRIVATE_KEY_BASE64);
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privKey));
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] encryptedData = Base64.getDecoder().decode(args[0]);
byte[] decryptedData = cipher.doFinal(encryptedData);
System.out.println("Decrypted message was: " + new String(decryptedData, "UTF-8"));
}
Output: Decrypted message was: attack at dawn!
One cool thing about the JDK's RSA implementation is that it uses Optimal Asymmetric Encryption Padding (OAEP) from PKCS#1, which has the effect that even identical messages will look different from each encryption.
Like previous commenters have mentioned, without seeing the full picture, there may be other security problems to address. But for what it's worth, I think this approach is better than using symmetrical keys, which still can be used with this encryption scheme. Then you would get what's called a hybrid cryptosystem, but there are APIs that do this for you.
Instead of storing the plaintext password in the source and checking against that you can store the encrypted password in the source (hard coded).
Then the user can enter the password, the code encrypts the password and compare the result of the encryption with the stored encrypted value to see if the password match. The password entered (not the encrypted password) is then used to encrypt/decrypt the data.
The encryption used should make the effort to reverse the encrypted password to the plaintext password hard/impossible.
Example:
You choose the encryption/decryption password to be This is my password1 (the one that is currently in the sources).
You encrypt the password with for instance SHA-256 and hard code it in the source: 9845735b525fa70b2651975022a44be268af1d4defadba9ab2a0301e0579534c.
Encrypt/decrypt app prompt for password.
User enter password.
App calculates the SHA-256 of the entered password and compare the result to 9845735b525fa70b2651975022a44be268af1d4defadba9ab2a0301e0579534c
If it matches the data is encrypted/decrypted with entered password This is my password1 using your code already in place.
If it does not match, give an error.
A hacker gets your sources and have access to the hash 9845735b525fa70b2651975022a44be268af1d4defadba9ab2a0301e0579534c and the algorithm you used. But he needs the This is my password1 password to decrypt the data. He can reverse or brute force the hash but that takes effort and time.
One can use seeds etc, but to keep them secret is then again the same issue.
It is probably not the most secure, I am no expert but it is better than having This is my password1 in the sources.

PyCrypto AES encryption for Server-Client comm

I'm developing a simple secure data exchange between Server-Client and having some problems at the time of implementing AES.
I've already implemented the Shared Key exchange (with public key crypto) and it works fine. The idea in my head was (pseudocode):
SERVER
ciphertext = AES.encrypt(sharedKey,data)
send(ciphertext)
CLIENT
ciphertext = receive()
plaintext = AES.decrypt(sharedKey,ciphertext)
And voilà. When I tried to implement that, I first found that there was an IV. I first tried setting it to all zeros, like this:
self.cipher = AES.new(self.Kshared, AES.MODE_CFB, '0000000000000000')
while( there is data to send ):
ciphertext = self.cipher.encrypt(data)
self.sendData(ciphertext)
Then, in the Client:
cipher = AES.new(Ksecreta, AES.MODE_CFB,'0000000000000000')
while( there is data to receive ):
plaintext = cipher.decrypt('0000000000000000'+data)[16:]
This works fine for the FIRST message, but not for the rest. I assume my problem might has something to do with the IV but I have no idea. Plus, the first implementation I found used a salt to generate another key and also a random IV but the problem is that the client has no idea of which salt/IV is the Server using. I guess you could send that via public key crypto but I first want a simple working AES crypto.
Thanks.
For your decryption code, there's no need to prepend the cipher text with the IV. Have you tried just plaintext = cipher.decrypt(data)?
It's safe to transmit the IV in clear text. So you can just generate it randomly, then send it along with the ciphertext outside of the communication. Something like self.sendData(iv + ciphertext) and later iv = data[:16] and ciphertext = data[16:]
Another common thing to consider is encoding - some transport formats don't play well with sending raw byes (which can include NULL characters). It's common to encode the ciphertext into base64 for transport. If you need that, look into base64.b64encode and base64.b64decode

PBKDF2 with HMAC in Java

I am working on a Java project where I must ensure the confidentiality and integrity of users password saved in a plaintext file.
To do so, I will write only a hash of the password in the file. More specifically, my intention is to write the hash of the password and a random salt, plus the random salt itself, to avoid the use of rainbow and lookup tables. I also want to use key-stretching with PBKDF2, to make the computation of the hash computationally expensive.
Finally, I would like to use a keyed hash algorithm, HMAC, for a final layer of protection.
I am trying to implement my thoughts in a Java code, and I have found some examples of the operations that I have presented above:
private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
return skf.generateSecret(spec).getEncoded();
}
The thing that I really cannot understand is how to input my secret key as the key used by the HMAC algorithm, as it doesn't seem an input to the function. I have looked through the Java documentation, but I cannot find a solution to my question.
At this point, I am not really sure if I understood correctly how the different part of the encryption mechanism work, so I would accept any help on the topic.
I think I see the confusion. You're apparently expecting your code to apply PBKDF2 then HMAC-SHA-1. That's not how it works: HMAC-SHA-1 is used inside PBKDF2.
The gist of PBKDF2 is to apply a function repeatedly which has the following properties:
it takes two arguments;
it returns a fixed-size value;
it is practically undistinguishable from a pseudo-random function.
HMAC-SHA-1 is such a function, and a common choice. There are other variants of PBKDF2, using HMAC-MD5, HMAC-SHA-256, or other functions (but these variants aren't in the basic Java library).
PBKDF2 takes two data inputs (plus some configuration inputs): the password, and a salt. If you want to include a secret value in the calculation, PBKDF2's input is the place for it: don't tack on a custom scheme on top of that (doing your own crypto is a recipe for doing it wrong). Append the pepper (secret value common to all accounts) to the salt (public value that varies between accounts).
Note that pepper is of limited usefulness. It's only useful if the hashes and the pepper secret value are stored in different places — for example, if the hashes are in a database and the pepper is in a disk file that is not directly vulnerable to SQL injection attacks.

CryptoAPI wrapped keys

With CryptoAPI, is there a way to decrypt (using CryptDecrypt) a key written into a SYMMETRICWRAPKEYBLOB?
In my c++ program, i wrap a symmetric key k1 with another symmetric key k2 into a symmetric key blob. I have a third key, k3, equal to k2 but with a different handle. My goal is to decrypt the blob with this key. I have already did it using a SIMPLEBLOB and a public key.
Thanks in advance for your attention.
Documentation here
As the documentation you link to says, the format used for SYMMETRICWRAPKEYBLOB follows RFC 3217. It is a weird format in which the data is encrypted, then reversed (last byte becomes first, and so on), and then encrypted again. Both encryptions use CBC. If you want to do it by hand, instead of using CryptImportKey(), then you will have to follow RFC 3217, with two calls to CryptDecrypt(), and your code will also have to do the byte reversal and the rest of the packaging.
Alternatively, import the key blob with CryptImportKey(), then export it again by encrypting with an asymmetric (RSA) key of your own, which you can then decrypt. At some point, Microsoft themselves were documenting that, in order to export a symmetric key "as is", the best way was to call CryptExportKey() with a handcrafted RSA public key with a public exponent equal to 1, i.e. not really a correct RSA key -- with such a public exponent, RSA encryption is mostly a no-operation.

BLOWFISH: Restore key from plainttext and hash?

Is it possible to restore the key from blowfish encrypted ciphertext and plaintext pairs?
I have several strings both encrypted and plain. But I can't remember key.
example of encrypted string 24026B7101030657757D01
decrypted string is AC C1312463
$key = '';
$plaintext = '';
$crypttext = '24026B7101030657757D01';
$cache = array();
while($plaintext != 'AC C1312463')
{
$key = random_string();
while(array_search($key,$cache) !== FALSE)
{
$key = random_string();
}
$cache[] = $key;
$bf = new Crypt_Blowfish($key);
$plaintext = $bf->decrypt($crypttext);
}
print_r($key);
die();
Let's say I have algorithm like this. How should function random_string should look like to get 32bit random key?
No decent cipher (including Blowfish) allows efficient key recovery no matter how many (plaintext, ciphertext) pairs you know.
What remains is a brute-force attack where you guess the key and then check if it matches a known pair. For sufficiently complex keys this becomes prohibitively expensive. So this will only work if your key was bad.
What you are proposing is esentially a known-plaintext attack, that said, as the wiki article points out, they haven't been a successful key recovery mechanism since the days of the Enigma.
To even get close to a modern key recovery system, you need to use a chosen plaintext attack like Differential cryptanalysis, which analyzes differences in ciphertext between specially chosen plaintext pairs to gain info about the key. That said, Blowfish isn't particularly susceptible to such attacks, so it won't help much anyways.
If you want to recover your key, you should consider the mechanisms that were used to generate it (is it derived from a password, how big is it, etc) and then come up with a way to brute force it, whether through a dictionary attack, iterating through all 32 bit integers, etc. a program called John the Ripper may help with applying this brute forcing as efficiently as possible.