I am reading an encrypted string from an application in xcode and I have to write a function that uses RSA decryption to decode and display the message.
I am completely lost on where to begin with this.
I have Openssl complied in xcode and I am using the openssl/rsa.h file.
I am trying to use the function:
RSA_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding);
But then I'd read somewhere on the Openssl main site that the function just returns a number and not the actual string. I also have no idea what paramenters to pass through.
The only reference I have found is the openssl/rsa.h file and looking at the functions it contains.
I've tried doing some research the past couple hours but I have no found any answers.
I was wondering if there is a simple function that I can pass my encrypted string and my private key (using a file or hardcoded) and it can return the decrypted string?
If not is there a guide on how to use Openssl with Objective C programming?
Please let me know if you need more information on the issue.
Thank you in advance.
You may want to look Apple's example which uses security transforms (this avoids openssl) in their Security Overview.
With a bit of luck you can do things with apple transforms and go with that programme.
If not - or if for some reason you really want to use openssl; then the openssl source contains the example file openssl-0.9.8t/apps/rsa.c which pretty much allows for selective cut-and-paste to make things work.
Doing man RSA_private_decrypt from the command line will show you the manual page (or from within Xcode to the man page). Or see http://www.openssl.org/docs/crypto/RSA_public_encrypt.html.
Example use for the above:
unsigned char in[] = { 1, 2, ... byte array to decrypt };
// size of that in byte array
int inlen = sizeof(in);
// output buffer size depends on the key type.
char * out = malloc(RSA_size(rsa));
int e = RSA_private_decrypt(inlen, in, out, rsa, RSA_PKCS1_PADDING);
where padding is one of the values from the man-page.
The value of rsa is a bit more complex to initialise as this is where you set up your keys and what not. Check the above rsa.c file for examples of various ways of filling it - it normally boils down to something like:
EVP_PKEY *pkey = load_key( ... , password,... );
rsa = EVP_PKEY_get1_RSA(pkey);
where load_key is borrowed from the app examples of openssl.
Related
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.
I am adding openssl to my application and I can send and receive data however so far it is not encrypted or checking the certificates.
I get the servers certificate with:
X509 *gCert = NULL;
X509_NAME *gCertName = NULL;
gCert = SSL_get_peer_certificate(sslConnection.ssl);
gCertName = X509_NAME_new();
gCertName = X509_get_subject_name(gCert);
certNameLen = strlen(gCertName);
memcpy(write_buffer, gCertName, certNameLen);
Then I write write_buffer to the SSL socket but what I receive in the other end is just gibberish.
How do I use X509_NAME? strlen does not work on it it seems? I get the length 4 which is the pointer size I think, not the buffer size...
And what encoding is X509_NAME? It does not seem like utf-8...
I know sending downstream works, if I just put 0xAA or 0XBB in the buffer it is received correctly on the other end.
You are fairly close. However X509_get_name returns a X509_NAME structure which you need to cast into a human readable string (or use 'as-is' for detailed and safer comparisons; as parsing/comparing plain ascii is a bit risky - a clever adversary could put things like 'C=' in the actual text).
The easiest of the lot is
X509 * gCertName =SSL_get_peer_certificate(con);
// if null - error out
const char * buf = X509_NAME_oneline(gCertName, 0, 0);
// if null - release memory and error out
printf("Client\t: %s\n", buf);
OpenSSL_free(buf);
X509_free(gCertName);
which nets you a one line approximation as a C \0 terminated string. Note that the _oneline functions are depricated - see the man pages of openssl for more elaborate ways to get a text rendition which is UTF8 and multi-line safe. But above is fine for simple things like pure ASCII westerncharset domain names without things like alternatives/variants.
I'm trying to test my RSA implementation's correctness with the RSACryptoPAD example in here: http://www.codeproject.com/Articles/10877/Public-Key-RSA-Encryption-in-C-NET
But it always creates different encryption results. Isn't RSA just a mod and power operation? But the program can decrypt all different encrypted texts correctly. My results are same with the http://nmichaels.org/rsa.py site. I think RSACryptoPAD is doing some other things?
The code uses RSACryptoServiceProvider. The line
byte[] encryptedBytes = rsaCryptoServiceProvider.Encrypt( tempBytes, true );
Tells it to encrypt using OAEP padding, which introduces randomness into the padding. The reason for doing this is so that encrypting the same plaintext will always yield different results (as you are seeing). This is a good thing, as it stops an information leak where an attacker sees you sent the same message multiple times.
There's a great historical example of why this is important. "AF is short of water"
This is how I have been generating my cryptographic keys until now:
unsigned char *salt; //8 salt bytes were created earlier
unsigned char *password; //password was obtained earlier
int passwordLength; //password length as well
unsigned char evp_key[EVP_MAX_KEY_LENGTH] = {"\0"};
unsigned char iv[EVP_MAX_IV_LENGTH];
EVP_BytesToKey(cipher, EVP_md5(), salt, password, //cipher is also given
passwordLength,
1, evp_key, iv);
The result is a key and an “initial value.” I can then use these two (evp_key and iv) along with the given cipher to encrypt my data.
Now that with Lion, Apple has deprecated the above code, I have the following question:
Question: How do I do the same thing with CommonCrypto? I just came across the CCKeyDerivationPBKDF() function. Is this the one I’m looking for? I can’t see how this is the case, since I don’t get any “initial value” back. I don’t know how to compare this CommonCrypto function with the old method.
In particular: This new function doesn’t seem to even support the MD5 algorithm—only the SHA1. How, then, can I create new code that is backwards compatible with my old codebase (and files it has created)?
I found the solution. To me, it seems impossible to derive the keys exactly the way OpenSSL does using any Apple’s methods. Instead, I just had to read how OpenSSL derive the key and initialization vector in the section “Key Derivation Algorithm” on the page http://www.openssl.org/docs/crypto/EVP_BytesToKey.html and simply mimic that.
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.