How to decrypt data using RSACng that is previously encrypted with RSACryptoServiceProvider - cryptography

I am migrating on RSACng for new version release from RSACryptoServiceProvider. However, as RSACryptoserviceProvider that is CAPI uses Little Endian Architecture and RSACng that is CNG API is using Big Endian Architecture, question is how can i decrypt the data using CNG Api that is previously encrypted using RSACryptoService provider (CAPI)?
I have already tried Array.reverse(cypherText) and tried to decrypt using CNG Api, but it is throwing the error, 'The parameter is incorrect'.
I have also tried the approach of decrypting half the cypher text because CNG API is using RSAEncryptionPadding.OaepSHA512 padding whereas CAPI uses OAEP padding.
My RSACryptoServiceProvider class is as below:-
public static void EncryptWithSystemKeyRSACryptoService(byte[]
plainBytes, bool representsUnicodeString, out string cypherText)
{
CspParameters cp = new CspParameters();
cp.KeyContainerName = regValue.ToString();
cp.Flags = CspProviderFlags.UseMachineKeyStore;
cp.KeyNumber = (int)KeyNumber.Exchange;
byte[] encBlockData=null;
using (RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cp))
{
res = CryptResult.GeneralError;
int keysize = rsaCSP.KeySize;
//This encrypts data and uses FOAEP padding
encBlockData = rsaCSP.Encrypt(plainBytes, true);
}
//Should i have to reverse the Byte order?
// I am doing Array.reverse for encrypted data as it follows little endian architecture and CNG Api follows Big Endian architecture
Array.Reverse(encBlockData);
cypherText = BitConverter.ToString(encBlockData );
cypherText = cypherText.Replace("-", "");
cypherText = cypherText.ToLower();
}
This is how i encrypt data with RSACryptoservice Provider (CAPI)
My RSACng class is as below :-
//I am calling this to use RSACng API to get private keys
private static byte[] SetPrivateAndPublicKeysAndDecrypt(byte[] cyphertext)
{
cp.KeyContainerName = regValue.ToString();
cp.Flags = CspProviderFlags.UseMachineKeyStore;
cp.KeyNumber = (int)KeyNumber.Exchange;
using (RSACryptoServiceProvider rsaCSP = new
RSACryptoServiceProvider(cp))
{
res = CryptResult.GeneralError;
keysize = rsaCSP.KeySize;
q = rsaCSP.ExportCspBlob(false);
RSAp = rsaCSP.ExportParameters(true);
}
//created cngKey
cngKey = CngKey.Import(q, CngKeyBlobFormat.GenericPublicBlob);
//created RSACng instance
RSACng rsacng = new RSACng(cngKey)
{
KeySize = keysize
};
rsacng.ImportParameters(RSAp);
//Decrypt using RSACng API using OAEPSHA512 padding
var plainText= crypto.Decrypt(cyphertext, RSAEncryptionPadding.OaepSHA512);
return plainText;
}
Expected result should be-> plainText successfully decrypted
Actual Resul-> Exception caught-> 'The parameter is incorrect'.

RSA ciphertext is defined to use statically sized, unsigned, big endian encoding in PKCS#1 (which specifies PKCS#1 v1.5 RSA encryption and OAEP encryption as implemented by most libraries). The function is called I2OSP within that standard, and the ciphertext should have the same size (in full bytes) as the key size. If it isn't big endian, then it does not conform to RSA / OAEP, in other words.
The same goes for normal ASN.1 encoded keys: they use dynamically sized, signed, big endian encoding according to DER (distinguished encoding rules). Those keys are defined in PKCS#1, PKCS#8 and X.509 standards, although they may also be embedded in a PKCS#12 compatible key store - for instance. Sometimes the keys are then PEM encoded as well to make them compatible with protocols that require text rather than binary.
So you should never have to reverse ciphertext or keys that use one of the standard encodings. That the calculations are performed internally on little endian (or not) is of no concern. This is true for about every modern cipher or other cryptographic primitive; the input / output is simply defined in bytes with a specific order, not numbers. Only very low level functions may possibly operate on e.g. words, which muddles the problem (but you won't find that in the MS API's).
Only Microsofts own proprietary (lame) key encodings may use little endian.
bartonjs is of course correct in the comments; you need to match the padding methods, and the default hash to be used for OAEP (or rather, the mask generation function MGF1 within OAEP) is SHA-1. There are plenty of other pitfalls to avoid, such as performing correct encoding / decoding of plaintext / ciphertext.

Related

How to create symmetric encryption key with Google Tink?

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.

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

Is the result of a RSA encryption guaranteed to be random

I use RSACryptoServiceProvider to encrypt some small blocks of data. For the solution I'm working on, it's important that if the same piece of source data is encrypted twice with the same public key, the result (the encrypted block of data) is not the same.
I have checked this with an example and it worked like I hoped. My question is now, if this behaviour is by design and guaranteed or if I have to add some random part to the source data for guaranteeing that data blocks with the same data can not be matched anymore after encryption.
Here is the example:
byte[] data=new byte[]{1,7,8,3,4,5};
RSACryptoServiceProvider encrypter = cert.PublicKey.Key as RSACryptoServiceProvider;
byte[] encryptedData = encrypter.Encrypt(data,true);
// encryptedData has always other values in, although the source data is always
// 1,7,8,3,4,5 and the certificate is always the same (loaded from disk)
The concrete question is for .net but maybe the answer can be given in general for all RSA-implementations if it is by design?
The text-book RSA encryption algorithm is deterministic:
ciphertext = plaintext ^ encryption-exponent mod modulus
(Here ^ is integer exponentiation, mod the remainder operation.)
But as you remarked, this does not provide a good security guarantee, as an attacker which can guess the plaintext can simply verify this guess by encrypting it himself and comparing the results.
For this reason, the official RSA specifications (and also all implementations used in practice) include some (partly random) padding, so we don't actually encrypt plaintext, but pad(plaintext):
ciphertext = pad(plaintext) ^ encryption-exponent mod modulus
Decryption:
plaintext = unpad( ciphertext ^ decryption-exponent mod modulus )
Only with this padding RSA is actually a secure encryption scheme.
A similar padding is also used for RSA signatures, to avoid easy forging of signatures.

How safe is my password decrypting class?

I'm a complete beginner to any sort of decrypting. I wrote a class that I think should be quite secure. Can you give me constructive criticism of how could I improve the algorithm.
package main;
import java.util.Random;
public class Main {
public static void main(String[] args) {
//we will be playing around with this string
new Main("1234567890abc");
}
private Random rnd;
private byte[] randoms;
/**
* Starts up RNG
* Prints out a test
*/
public Main(String password) {
//random long generated from the password
long randomLong = randomNumber(password);
//Random class using randomLong as seed
rnd = new Random(randomLong);
randoms = new byte[password.length()];
//Array of random bytes generated with rnd
rnd.nextBytes(randoms);
System.out.println(randomNumber(password));
String cryped = encrypt(password);
String decryped = decrypt(cryped);
System.out.println(cryped);
System.out.println(decryped);
}
/**
* Encrypts the password.
*/
private String encrypt(String password) {
char[] chars = password.toCharArray();
for (int i = 0; i < chars.length; i++) {
chars[i] = (char) (chars[i] + randoms[i]);
}
return String.valueOf(chars);
}
/**
* Decrypts an allready encryped password.
*/
private String decrypt(String crypted) {
char[] chars = crypted.toCharArray();
for (int i = 0; i < chars.length; i++) {
chars[i] = (char) (chars[i] - randoms[i]);
}
return String.valueOf(chars);
}
/**
* Finds a random number BASED ON PASSWORD
*/
private long randomNumber(String password)
{
char[] chars = password.toCharArray();
long number = 0;
for (char c : chars) {
number += c;
}
number *= chars.length;
return number;
}
}
The class is written in Java but should be readable to anyone.
Don't reinvent your own cryptography in real life (is this an excercise?) Even experts make mistakes. Use something that's been publically scrutinized.
The java random number generator is not cryptographically secure. With a long enough text to encrypt, patterns will emerge that can permit various information leaks upto and including revealing the password (but see point three) and the plaintext.
You use the password to seed the random number generator. This is a standard (and fine) idea, but you do so using an algorithm that is invariant to permutation! i.e. Your encryption treats "sinecure" and "insecure" or other passwords that are anagrams as equivalent (and probably others too). For a strong password of up to 16 letters and no codepoints beyond 255, the highest reachable seed is 255*16*16 = 65280; but there are even fewer possibilities since there are seeds lower than this which are not reachable. On my keyboard, bruteforcing shows just 9734 different seeds for passwords consisting solely of keyboard-writable characters excluding newline (I count 95) of up to 16 characters in length; that's less than 1 bit of entropy per letter.
CodeInChaos has a few additional observations in his answer: you're using a stream cipher (even harder to get right!). You're also encrypting the password which suggests you may be looking for a hash not an encryption function, (or is that just an example?).
By the way if you're trying to store passwords; don't - not even encrypted! See the sony fiasco for why; you may get hacked, you may lose your password database, and your encryption keys may be known to the attacker. Instead, use standard, best-practice password hashing (and prefer a standard preexisting component if possible). Such a system should at least use a secure hash such as sha1 or better; passwords should be individually salted (the salt can be stored plaintext), and the process should be made computationally expensive to make brute-force unattractive. See http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html for details.
Horribly broken in more than one way.
Your key is 64 bit, a bit small for today. But that's the least of your worries for now.
I see a non cryptographic PRNG. You need to use a crypto PRNG.
You're reusing a key in a stream cypher. Stream cyphers are notorious for being hard to use correctly. In this mode of operation it basically behaves like a one-time-pad generated by a PRNG. Once you reuse a key in such a mode, your crypto is broken.
Suppose an attacker knows encrypt(p1) and encrypt(p2). Then he can calculate encrypt(p1)-encrypt(p2) which is identical to p1-p2.
Your effective key size is much smaller than 64bit. The sum of chars in a string is <2^16*length. And for most characters it's even <128. So you're key will usually be a number <1000'000. That's trivial to brute force.
Each element in randoms is a byte i.e. 8 bit. A char is 16 bit. So you're not adding modulo 256. Thus you leak information about the encrypted password.
And to improve it, throw out your own algorithm entirely and use a well know, reviewed algorithm. Inventing your own algorithm is a bad idea unless you're a cryptography expert. And even expert make mistakes relatively often.
And do you really need password decryption (i.e. is it a password store), or is password hashing enough?
My suggestion is to put your master password in a key-derivation-function (PKDF2 is a common choice). Then use the key this function returns to encrypt the rest of your data file using AES.