How to use initWithModulus function in MyCrypto library? - iphone

I use MyCrypto library for a IPhone app. The program will comunicate with a web service that is writen by WCF.The service will provide a public key by providing modulus and exponent. Thus, we need use initWithModulus to create a public key. The code is as following.
MYPrivateKey *pair = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 2048];
MYPublicKey *pub = pair.publicKey;
NSData * outModulus;
unsigned outExponent;
[pub getModulus:&outModulus exponent:&outExponent];
MYPublicKey *serverKey = [[MYPublicKey alloc] initWithModulus: outModulus exponent: outExponent];
NSString *tmpStr = #"test!";
NSData *tmpData = [tmpStr dataUsingEncoding: NSASCIIStringEncoding];
NSData *crypted = [serverKey rawEncryptData: tmpData];
NSData *crypted2 = [pub rawEncryptData: tmpData];
For test, I use initWithModulus to create a publickey. Then the same data are encrypted with the original key and the new one. But the lengths of the two encrypted data are different. How shoud I do?

What are the mismatched lengths? When I run this code (in the iOS 4 simulator) it works, and the length of the encrypted data is 256 bytes.
If you try encrypting with the original private key and then decrypting with the reconstituted public key, does that work?

Related

signing an NSString using a private key generated with OpenSSL

I'm trying to use RSA to sign a token within a HTTP header that I have to pass to a web service - the requirements are that I should encrypt using my own private key and give them my public key. This is used purely so verify that the message was sent by me.
I'm aware of many similar questions on SO but I've been through many attempts so far this morning and am still no closer to something I assumed would be trivial.
I can find many examples of using RSA and encrypting using a public key, but my requirement is for me to sign with the private key.
It looks (from initial attempts) that the apple sample security code and most other examples that borrow from it always generate a private/public keypair using keychain - I would prefer to generate my keys using OpenSSL so I can distribute the public key to my client.
I've managed to generate some keys and it looks like I can load the private key using this code (apologies, I can't recall the source as I've been mixing implementations for hours):
-(SecKeyRef) getPrivateKeyRef {
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"rsaPrivate" ofType:#"p12"];
NSData *p12Data = [NSData dataWithContentsOfFile:resourcePath];
NSMutableDictionary * options = [[NSMutableDictionary alloc] init];
SecKeyRef privateKeyRef = NULL;
//change to the actual password you used here
[options setObject:#"xxxx" forKey:(__bridge id)kSecImportExportPassphrase];
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
OSStatus securityError = SecPKCS12Import((__bridge CFDataRef) p12Data,
(__bridge CFDictionaryRef)options, &items);
if (securityError == noErr && CFArrayGetCount(items) > 0) {
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict,
kSecImportItemIdentity);
securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);
if (securityError != noErr) {
privateKeyRef = NULL;
}
}
CFRelease(items);
return privateKeyRef;
}
which seems to return me a valid SecKeyRef but I don't know how to use this to sign an NSString.
There seems to be so many ways to tackle this question (build OpenSSL and link to it, use Apple's keychain methods, use a partially complete library on GitHub) but I keep reaching a dead end - it would be ideal to get a proper, complete solution to this one.
Something along the lines of:
NSString* signedString = [rsaHelper signString: #"Hello, World!" WithPrivateKey:#"rsaPrivate.p12"];
And given a string encrypted with the public key:
NSString* decryptedString = [rsaHelper decryptString: #"DK5tkgkfjkJJft=" WithPrivateKey:#"rsaPrivate.p12"];
would be valuable! Please note, I'm not afraid of writing this code myself in any way, but would appreciate a nudge in the right direction :-)

Cannot figure out how to publish public key generated on iPhone

I am using the commoncrypto library on the iPhone to create a pair of RSA keys and I am trying to send the public key to a server (Python) so that I can use it to verify a signature sent from the phone.
I'm using the exact code from the CommonCrypto example using the method getPublicKeyBits() which looks like this:
`- (NSData )getPublicKeyBits {
OSStatus sanityCheck = noErr;
NSData publicKeyBits = nil;
NSData* publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
CFDataRef cfresult = NULL;
NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];
// Set the public key query dictionary.
[queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
[queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnData];
// Get the key bits.
sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef*)&cfresult);
if (sanityCheck != noErr)
{
publicKeyBits = nil;
}
else
{
publicKeyBits = (__bridge_transfer NSData *)cfresult;
}
return publicKeyBits;
}`
The problem is that I don't know how, exactly, the key is being stored or how to pass it. I am using the getPublicKeyBits() to get it in a NSData structure, and I've imported a library to encode it in base64. I'm getting a key (SHA1, I'd like to move to SHA256, but that's secondary to getting this working) and the base64 version looks like other keys I've found here and in other people solving RSA problems.
I've been trying to use the M2Crypto library in Python and when I try to verify I'm getting the error "RSA Error: No Start Line". Here's the code I'm using to receive the public key:
pubKey = request.form['publickey']
uid = uuid4().hex
while not unique(uid, User):
uid = uuid.uuid4().hex
user = User(uid, email, secret, pubKey)
And the code I'm using to check the signature:
def validate(sessionKey, sig, pem):
bio = BIO.MemoryBuffer(pem.encode('ascii'))
rsa = RSA.load_pub_key_bio(bio)
pubkey = EVP.PKey()
pubkey.assign_rsa(rsa)
pubkey.reset_context(md='sha1')
pubkey.verify_init()
pubkey.verify_update(sessionKey)
return pubkey.verify_final(sig)
I'm really stumped as to what I'm doing wrong but I feel like I'm getting close. If my whole method is not the way you'd do it, I'd love to hear any other way to generate RSA keys on the phone, publish the public key to a server, and then verify a signature from the phone on that server.
Thanks!
You can use the getPublicKeyBits method from SecKeyWrapper in the Apple CryptoExercise code
https://developer.apple.com/library/ios/#samplecode/CryptoExercise/Listings/Classes_SecKeyWrapper_h.html
This will get you the DER encoded binary data. Then use the following method to load it into M2Crypto in Python: (Basically, just base64 it and invoke one method.)
https://stackoverflow.com/a/5765576/584616
I have an ARC enabled version of this getPublicKeyBits method, but I haven't gotten around to posting it yet.
Update - on re-reading your question, the answer is actually here:
How to find out the modulus and exponent of RSA Public Key on iPhone/Objective C
You can use this to get the modulus and exponent as NSData, which you should be able to easily convert into base64 or your representation of choice.
The underlying implementation of M2Crypto is OpenSSL. OpenSSL will not import your pure public key as you exported it but only if it is "embedded" in a possibly self-signed certificate. Check out how to create a self-signed certificate with Common Crypto or Security framework, embed your public key and sign it with your private key, extract its data and send it to your server: it should work.
See also openssl_pkey_get_public not open public key, "no start line" error (the second answer)

iPhone - Decrypting an AES-encrypted message with a different key than the one used to encrypt

I'm just coding basic "encrypt" and "decrypt" methods for AES on iPhone, using CCrypt.
I've been running a few tests and I was really struck about finding that, sometimes, if you try to decrypt an encrypted text using a key different than the one that was used to encrypt the plain text CCrypt would not return any errors.
Here is an example:
- (void) testDecryptTextWithTheWrongKey {
NSData *encryptKey = [Base64 decodeBase64WithString:#"+LtNYThpgIlQs2CaL00R6AuG2C/i6U1Vt1+6wfFeFMk="];
NSData *decryptKey = [Base64 decodeBase64WithString:#"yg7BvhM8npVGpAFpAESDn3IRWpe6qeQWaa1rwHiTsyU="];
NSString *plainText = #"The text to be encrypted";
NSData *plainTextData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
NSData *encrypted = [LocalCrypto encryptText:plainTextData key:encryptKey error:&error];
assertThat(error, nilValue());
assertThat(encrypted, notNilValue());
error = nil;
NSData *decrypted = [LocalCrypto decryptText:encrypted key:decryptKey error:&error];
assertThat(error, notNilValue());
assertThat(decrypted, nilValue());
}
My encrypt and decrypt methods defined in LocalCrypto simply call an internal "executeCryptoOperation" method indicating that they want to encrypt or decrypt:
+ (NSData *) executeCryptoOperation:(CCOperation)op key:(NSData *) key input:(NSData *) input error:(NSError **)error {
size_t outLength;
NSMutableData *output = [NSMutableData dataWithLength:input.length + kCCBlockSizeAES128];
CCCryptorStatus result = CCCrypt(op, // operation
kCCAlgorithmAES128, // Algorithm
kCCOptionPKCS7Padding | kCCOptionECBMode, // options
key.bytes, // key
key.length, // keylength
nil, // iv
input.bytes, // dataIn
input.length, // dataInLength,
output.mutableBytes, // dataOut
output.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result == kCCSuccess) {
output.length = outLength;
} else {
*error = [NSError errorWithDomain:kCryptoErrorDomain code:result userInfo:nil];
return nil;
}
return output;
}
Well, my question is: is it normal that CCrypt returns kCCSuccess when we try to decrypt the encrypted text with a different key than the one used during the encrpytion? Am I missing something or doing something wrong?
It is true that even when CCrypt returns success for the decryption, I can't get a proper NSString out of the resulting data but I would certainly expect CCrypt to return some sort of error in this situation (as Java would probably do).
If this is the normal behavior, how am I supposed to know if the decrypt operation returned the real plain text or just a bunch of bytes that don't make any sense?
There is a similar question here, but the answer doesn't really convince me: Returning wrong decryption text when using invalid key
Thanks!
There are cipher algorithms which include padding (like the PKCS#5 padding in your Java implementation), and there are ones which don't.
If your encryption algorithm used padding, the corresponding decryption algorithm expects that there will be well-formed padding in the decrypted plaintext, too. This serves as a cheap partial integrity check, since with a wrong key the output likely will not have a right padding. (The chance that a random n-byte block (n=16 for AES) has a valid PKCS#5 padding is 1/256 + 1/(256^2) + ... + 1/(256^n), which is only slightly more than 1/256.)
It might be that your objective-C CCCrypt function does not check that the padding is valid, only its last byte (or even only some bits of this last byte), to see how many bytes were padded (and are now to be cut off).
If you want to make sure that the key is right, encrypt some known part of the plaintext, and error out if it is not in the decrypted part. (But don't do this with ECB mode, see below.)
If you also want to make sure that the data was not modified, also use a MAC, or use a combined authenticated encryption mode of operation for your block cipher.
Another note: You should not use ECB mode, but instead a secure mode of operation (about any other mode indicated in this article and supported by your implementation will do - standard nowadays is CBC or CTR mode). Some modes (like CFB, OFB and CTR) don't need padding at all.
You're missing the fact that the decryption function has no idea whatsoever what the plaintext (decrypted data) is supposed to look like.
As far as the decryption function is concerned, it got a key and a ciphertext from you, applied the decryption routine to the ciphertext using the key you provided, and no errors arose. Hence, success.
It's your job to verify that the plaintext you got was actually correct/on the format you expected it to be.

iPhone encrypt function that would be decrypt on php server

I want to write encrypt function in iPhone application that would be decrypt on server in php,
Decrypt function in php is this
function decrypt($input_text)
{
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$enc_key = "0e9d083f3514a69243bb8f1395d332c1";
$out = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $enc_key, $input_text, MCRYPT_MODE_ECB, $iv);
return $out;
}
I'm using following encryption code in iPhone
+(NSString*) encrypt:(NSString*) str key:(NSString*) key
{
NSString *key =key;
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero( keyPtr, sizeof(keyPtr) ); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
char *dataIn = [str UTF8String];
char dataOut[500];// set it acc ur data
bzero(dataOut, sizeof(dataOut));
size_t numBytesEncrypted = 0;
CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,kCCOptionPKCS7Padding|kCCOptionECBMode, keyPtr,kCCKeySizeAES128, NULL, dataIn, strlen(dataIn), dataOut, sizeof(dataOut), &numBytesEncrypted);
NSString* strResult = [[[NSString alloc] initWithCString:dataOut] autorelease];
return [strResult copy];
}
but didn't get the original result.
Please anybody can correct me where i'm wrong
Try:
As said, use the same key length in both cases.
In the CCCrypt call you don't store the iv that was generated, instead you pass NULL. You should store this and somehow transport it along the message to your PHP code. There, instead of generating a new, random iv you would reuse the existing one generated by the iPhone.
On top of that, mcrypt does not support PKCS7Padding (also often referred to as PKCS5Padding), so unfortunately you need to implement it yourself. In your case, you first decrypt the iPhone's input and then apply the pkcs5_unpad function described in that article afterwards.
You are using AES with 256-bit key in the decryption and with 128-bit key in the encryption. These are entirely different algorithms.

iPhone and HMAC-SHA-1 encoding

im trying to get a call to amazon web service and im stuck on getting the signature, looked at this but i still have a question on it.
using this example what is the
NSData *keyData;
NSData *clearTextData
? what do i need to pass for these two values?
/*
inputs:
NSData *keyData;
NSData *clearTextData
*/
uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0};
CCHmacContext hmacContext;
CCHmacInit(&hmacContext, kCCHmacAlgSHA1, keyData.bytes, keyData.length);
CCHmacUpdate(&hmacContext, clearTextData.bytes, clearTextData.length);
CCHmacFinal(&hmacContext, digest);
NSData *out = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]
I just spent like 4 hours Googling and looking for ways to calculate an unkeyed SHA1 on the iPhone that would match the results of the sha1() function in php. Here was the result:
#import <CommonCrypto/CommonDigest.h>
NSString *hashkey = <your data here>;
// PHP uses ASCII encoding, not UTF
const char *s = [hashkey cStringUsingEncoding:NSASCIIStringEncoding];
NSData *keyData = [NSData dataWithBytes:s length:strlen(s)];
// This is the destination
uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0};
// This one function does an unkeyed SHA1 hash of your hash data
CC_SHA1(keyData.bytes, keyData.length, digest);
// Now convert to NSData structure to make it usable again
NSData *out = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
// description converts to hex but puts <> around it and spaces every 4 bytes
NSString *hash = [out description];
hash = [hash stringByReplacingOccurrencesOfString:#" " withString:#""];
hash = [hash stringByReplacingOccurrencesOfString:#"<" withString:#""];
hash = [hash stringByReplacingOccurrencesOfString:#">" withString:#""];
// hash is now a string with just the 40char hash value in it
Hopefully this will help others who are struggling with SHA1 on the iPhone
If you are calling the Amazon web service too look up prices or product details, your Amazon web service key will be disabled and your app will stop working.
Look at the terms of service of the Amazon Web Services, use by mobile clients is strictly disallowed:
https://affiliate-program.amazon.com/gp/advertising/api/detail/agreement.html
I found this out the hard way when my own application had my AWS key disabled in a production app. I had read the TOS, but it was not really there as you can see by the link above to some other obscure detail of use. You wouldn't think the affiliate program would have anything to do with the API, but it does.
You can find details of other apps blocked at this TechCrunch article:
http://www.techcrunch.com/2009/07/07/amazon-killing-mobile-apps-that-use-its-data/
Just giving you a heads up and hopefully saving you a lot of work.
// This is my code used in my Twitter connection, and working well for me.
// KeithF's code was a big help!
//
// This is a category added to NSData.
#implementation NSData (EOUtil)
- (NSData*)dataByHmacSHA1EncryptingWithKey:(NSData*)key
{
void* buffer = malloc(CC_SHA1_DIGEST_LENGTH);
CCHmac(kCCHmacAlgSHA1, [key bytes], [key length], [self bytes], [self length], buffer);
return [NSData dataWithBytesNoCopy:buffer length:CC_SHA1_DIGEST_LENGTH freeWhenDone:YES];
}
#end
Take a look at CocoaCryptoHashing for the SHA1 encoding
I posted one solution to this here, that returns the Base64 encoded data that AWS requests.
Apple's iOS developer library has provided an excellent sample titled CryptoExercise which includes a simple function:
- (NSData *)getHashBytes:(NSData *)plainText" to get a SHA-1 hash.
You can see this
maybe it helps you.