iOS RNCryptor (encrypting) and Node.JS jscryptor (decrypting) - ios

I'm passing a base 64 string created with RNCryptor on iOS and am unable to decrypt it. When adding some console.logs to the Node.JS library's Decrypt function, it stops at the !_hmac_is_valid comparison. I can, however, use the .NET library to decrypt and the output is fine.
iOS
- (void) sendCommand: (NSString *) command {
NSData *data = [command dataUsingEncoding:NSUTF8StringEncoding];
NSString *key = #"1234567890123456789012";
NSData *encryptedData = [RNEncryptor encryptData:data
withSettings:kRNCryptorAES256Settings
password:key
error:&error];
if (currentPeripheral != nil && currentPeripheral.state == CBPeripheralStateConnected) {
[currentPeripheral writeValue:encryptedData forCharacteristic:currentCharacteristic type:CBCharacteristicWriteWithResponse];
}
}
Node.JS
function decryptString(data) {
const RNCryptor = require('jscryptor');
const password = '1234567890123456789012';
try {
console.log(RNCryptor.Decrypt(data.toString('base64'), password).toString('ascii')); // undefined when trying to decrypt the iOS string
}
catch (e) {}
}
VB.NET test
Public Function DecryptString(encryptedString) As String
Dim password = "1234567890123456789012"
Dim decryptor As New Decryptor
Dim decryptedData As String = decryptor.Decrypt(encryptedString, password)
Return decryptedData
End Function

Related

Objective C- RSA digital signature from objective c sent to JAVA server can't be verified

Im generating and signing data with RSA private key from objective C,
and sending signed data with string RSA public key to JAVA server,
then the server must be verifying the signed data with the public key I provided,
but it always fails.
Can anyone tell me what is wrong with the codes on Objective C side.
Here's how I'm generating RSA key pairs
KeyChainWrapper* keychainTemp = [[KeyChainWrapper alloc] initWithService:[NSString stringWithFormat:#"SS%#TEMP", KEYCHAINSERVICEID] withGroup:nil];
NSDictionary* attributes =
#{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,
(id)kSecAttrKeySizeInBits: #2048
};
CFErrorRef cfError = NULL;
SecKeyRef privateKeySec = SecKeyCreateRandomKey((__bridge CFDictionaryRef)attributes, &cfError);
if (!privateKeySec) {
CFBridgingRelease(cfError);
return;
}
SecKeyRef publicKeySec = SecKeyCopyPublicKey(privateKeySec);
NSData* dataPublicKey = (__bridge_transfer NSData *)SecKeyCopyExternalRepresentation(publicKeySec, &cfError);
NSData* dataPrivateKey = (__bridge_transfer NSData *)SecKeyCopyExternalRepresentation(privateKeySec, &cfError);
if (dataPublicKey && dataPrivateKey) {
[keychainTemp insert:[NSString stringWithFormat:#"%#RSAPUBKEYTEMP", strType] DATA:dataPublicKey];
[keychainTemp insert:[NSString stringWithFormat:#"%#RSAPRIKEYTEMP", strType] DATA:dataPrivateKey];
}
if (publicKeySec) { CFRelease(publicKeySec); }
if (privateKeySec) { CFRelease(privateKeySec); }
then convert dataPublicKey to strPublicKey to send to the server,
and here's how I sign the data.
strRsaSign = [self sha256HashFor:[NSString stringWithFormat:#"%#%#%#%#", userId, systemId, [self SSGET_UNIQUE_DEVICE], strPublicKey]];
NSData* dataStrRSASign = [strRsaSign dataUsingEncoding:NSUTF8StringEncoding];
size_t signatureBytesSize = SecKeyGetBlockSize(privateKey);
uint8_t *signatureBytes = (uint8_t *)malloc(signatureBytesSize * sizeof(uint8_t));
memset((void *)signatureBytes, 0x0, signatureBytesSize);
OSStatus status = SecKeyRawSign(privateKey,
kSecPaddingPKCS1,
(unsigned char *)dataStrRSASign.bytes,
dataStrRSASign.length,
signatureBytes,
&signatureBytesSize
);
base64StrRSASign = [[NSData dataWithBytes:signatureBytes length:signatureBytesSize] base64EncodedStringWithOptions:0];
And then, I send the base64StrRSASign and strPublicKey to the server,
to let server verifies the base64StrRSASign with strPublicKey.
What can I possibly be missing here if anyone can tell me...

OSX Generated key can't encrypt (SecKeyCreateRandomKey & SecKeyCreateEncryptedData)

I am basically follow this guide to generated a private key, copy the public key, and then encrypt a message. However, it gives me the error (OSStatus error -67712 - CSSM Exception: -2147415791 CSSMERR_CSP_INVALID_KEY_REFERENCE).
Initially, I thought I set the attributes incorrectly. However, if I create the public key (with the same attributes) by the SecKeyGeneratePair() function, everything works perfectly. Is it weird?
void TestEncryptDecrpt() {
OSStatus status;
NSData* tag = [#"com.example.keys.mykey" dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary* attributes =
#{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,
(id)kSecAttrKeySizeInBits: #1024,
(id)kSecPrivateKeyAttrs:
#{ (id)kSecAttrIsPermanent: #YES,
(id)kSecAttrApplicationTag: tag,
},
};
CFErrorRef error = NULL;
SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)attributes, &error);
SecKeyRef publicKey = SecKeyCopyPublicKey(privateKey);
// *** it will work if I generate the key by SecKeyGeneratePair ***
// status = SecKeyGeneratePair( (__bridge CFDictionaryRef)attributes, &publicKey, &privateKey );
// start encrypt and decrypt a message
static char const kMessage[] = "This is a secret!\n";
SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionRaw;
BOOL canEncrypt = SecKeyIsAlgorithmSupported(publicKey, kSecKeyOperationTypeEncrypt, algorithm);
NSData* plainData = [NSData dataWithBytes:kMessage length:sizeof(kMessage)];
canEncrypt &= ([plainData length] < (SecKeyGetBlockSize(publicKey)-130));
NSData* cipherText = nil;
if (canEncrypt) {
CFErrorRef error = NULL;
cipherText = (NSData*)CFBridgingRelease( SecKeyCreateEncryptedData(publicKey, algorithm, (__bridge CFDataRef)plainData, &error));
if (!cipherText) {
NSError *err = CFBridgingRelease(error); // ARC takes ownership
// Handle the error. . .
NSLog(#"error = %#, %#", [err userInfo], [err localizedDescription]);
}
}
}
Problem solved. You need the "kSecAttrIsPermanent" property as well in the public key setting.
Not sure why this is not mentioned in the example.

AES Decryption in objective c where encryption in .net

Hello friends I stuck in decryption of data. Server side data is encrypted by .net, i tried many codes but unable to decrypt.
In android data is decrypted by this function
public static String doDecrypt(String data, String key){
String decryptedData = null;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-8");
int len = b.length;
if (len > keyBytes.length)
len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] results = new byte[data.length()];
try {
results = cipher.doFinal(Base64.decode(data,Base64.DEFAULT));
} catch (Exception e) {
Log.i("Erron in Decryption", e.toString());
}
Log.i("Data", new String(results, "UTF-8"));
decryptedData = new String(results, "UTF-8");
}
catch (Exception e) {
e.printStackTrace();
return null;
}
return decryptedData;
}
its working fine in android, but while decrypting in objective c its gives only null.
I used some link that are below:-
nsdata , fwencryption , RNCryptor
But it only gives null value when decrypting in NSString.
For example you can check a demo for decryption
data:-1YbDEEZGnc5EtZY040AaSP233AXZHJVAZb74sCQHm+BX72N5nM81ygDsRHhF8KMk
key- test#123456789
I used this code in Objective c
#import "ViewController.h"
#import "NSData+AES.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *testData = [self decode:#"1YbDEEZGnc5EtZY040AaSP233AXZHJVAZb74sCQHm+BX72N5nM81ygDsRHhF8KMk"];
NSLog(#"Dtata%#",testData);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSString*)encode:(NSString*)plainString {
//convert 'plainString' to NSData using NSUTF8StringEncoding
NSData *plainData = [plainString dataUsingEncoding:NSUTF8StringEncoding];
//encrypt data with AES encryption
NSData *AESData = [plainData AES128EncryptedDataWithKey:#"test#123456789"];
//return base64 encoded string
return [AESData base64EncodedStringWithOptions:0];
}
-(NSString*)decode:(NSString*)encodedString {
//convert 'encodedString' to base64 decoded data
NSData *base64Data = [[NSData alloc] initWithBase64EncodedString:encodedString options:0];
//decode using AES encryption
NSData *AESData = [base64Data AES128DecryptedDataWithKey:#"test#123456789"];
//return string from AES decoded data
return [[NSString alloc] initWithData:AESData encoding:NSUTF8StringEncoding];
}
Please anyone can help me out. I am stuck in this.Thanks in advance.

RNCryptor: get public key as NSString

I'm successfully encrypting/decrypting data in iOS using RNCryptor.
I'm trying to get the public key to send to a server, so it can encrypt some data.
NSString *saltString = #"salt'n'peppa";
NSData *salt = [saltString dataUsingEncoding:NSUTF8StringEncoding];
NSData *key = [RNCryptor keyForPassword:password
salt:salt
settings:kRNCryptorAES256Settings.keySettings];
At this point, key has some data in it. However, I can't seem to work out how to get the public key as a string:
NSString *publicKey = [[NSString alloc] initWithData:key encoding:NSUTF8StringEncoding];
I've tried different encodings but nothing seems to work.
Here is the keyForPassword method from RNCryptor:
+ (NSData *)keyForPassword:(NSString *)password salt:(NSData *)salt settings:(RNCryptorKeyDerivationSettings)keySettings
{
NSMutableData *derivedKey = [NSMutableData dataWithLength:keySettings.keySize];
// See Issue #77. V2 incorrectly calculated key for multi-byte characters.
NSData *passwordData;
if (keySettings.hasV2Password) {
passwordData = [NSData dataWithBytes:[password UTF8String] length:[password length]];
}
else {
passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
}
// Use the built-in PBKDF2 if it's available. Otherwise, we have our own. Hello crazy function pointer.
int result;
int (*PBKDF)(CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen,
const uint8_t *salt, size_t saltLen,
CCPseudoRandomAlgorithm prf, uint rounds,
uint8_t *derivedKey, size_t derivedKeyLen);
PBKDF = CCKeyDerivationPBKDF ?: RN_CCKeyDerivationPBKDF;
result = PBKDF(keySettings.PBKDFAlgorithm, // algorithm
passwordData.bytes, // password
passwordData.length, // passwordLength
salt.bytes, // salt
salt.length, // saltLen
keySettings.PRF, // PRF
keySettings.rounds, // rounds
derivedKey.mutableBytes, // derivedKey
derivedKey.length); // derivedKeyLen
// Do not log password here
NSAssert(result == kCCSuccess, #"Unable to create AES key for password: %d", result);
return derivedKey;
}
I get the feeling I'm doing something majorly wrong as googling comes up with very little.
The key isn't a string, it's data. Just a random (sort of) series of bytes. The only real way to convert it to a string to send to a server would be to encode the bytes. A common method would be to use a base 64 encoding. Then the server could covert the base 64 encoded string back into the raw bytes of the key.

encrypt or sign string with public key in iOS with Objective C

i have a private key. Text File that begins like "--- begin private key..."
i want to use that key to encrypt an NSString. since its the private key, better call it sign an NSString.
can this be done without any external frameworks?
the result should be equivalent to the php openssl_sign function.
The iOS SDK framework you will need to use is called CommonCrypto. Here's a very good article that describes the right way to go about it.
Edit: I missed the part about compatibility with the PHP function openssl_sign. The solution below resolves that.
The way to do this so that it's compatible with the PHP function openssl_sign is to use the OpenSSL library. The openssl_sign function uses OpenSSL's EVP API internally to encrypt the input string using the private key and compute the SHA-1 hash digest of that encrypted string. It's common then to convert this hash digest into a Base64-encoded string.
Unfortunately, the iOS SDK does not include OpenSSL, but it's easy to build it. The following instructions for building OpenSSL for iOS are taken from this blog post and are reproduced here to provide a complete solution to the question.
In Terminal, follow those steps to build the OpenSSL library for iOS:
# Make a directory in which to run the build
mkdir ~/openssl-ios
cd ~/openssl-ios
# Download the openssl source (verify the file before using it in production!)
curl -O http://www.openssl.org/source/openssl-1.0.1e.tar.gz
# Download the openssl iOS build script
curl -O https://raw.github.com/Raphaelios/raphaelios-scripts/master/openssl/build-openssl.sh
# Make the build script executable
chmod +x build-openssl.sh
# Run the script (takes about 3min on an Intel Core i5)
./build-openssl.sh
This will take a few minutes but once it's complete you can verify that the build library is a universal library that you can use on iOS devices and in the iOS Simulator using the following command:
lipo -info ~/openssl-ios/lib/*.a
Now that the OpenSSL library has been built, let's got on with writing the code to sign a string.
First, we need to setup the Xcode project to link against the OpenSSL library. Drag & drop both libcrypto.a and libssl.a to the Frameworks group in the Project Navigator of your iOS project. In your project's Build Settings, add the following to the Header Search Paths setting:
~/openssl-ios/include/include
Next, create a new Objective-C Category file called openssl_sign on the NSString class. In NSString+openssl_sign.h, define the following interface:
#interface NSString (openssl_sign)
- (NSString *)signStringWithPrivateKey:(NSData *)privateKey;
#end
In NSString+openssl_sign.m, add the following header imports:
#import <openssl/evp.h>
#import <openssl/pem.h>
And add the following implementation of signStringWithPrivateKey::
#implementation NSString (openssl_sign)
- (NSString *)signStringWithPrivateKey:(NSData *)privateKeyData
{
BIO *publicBIO = NULL;
EVP_PKEY *privateKey = NULL;
if ((publicBIO = BIO_new_mem_buf((unsigned char *)[privateKeyData bytes], [privateKeyData length])) == NO) {
NSLog(#"BIO_new_mem_buf() failed!");
return nil;
}
if (PEM_read_bio_PrivateKey(publicBIO, &privateKey, NULL, NULL) == NO) {
NSLog(#"PEM_read_bio_PrivateKey() failed!");
return nil;
}
const char * cString = [self cStringUsingEncoding:NSUTF8StringEncoding];
unsigned int stringLength = [self length];
unsigned char * signatureBuffer[EVP_MAX_MD_SIZE];
int signatureLength;
EVP_MD_CTX msgDigestContext;
const EVP_MD * msgDigest = EVP_sha1();
EVP_MD_CTX_init(&msgDigestContext);
EVP_SignInit(&msgDigestContext, msgDigest);
EVP_SignUpdate(&msgDigestContext, cString, stringLength);
if (EVP_SignFinal(&msgDigestContext, (unsigned char *)signatureBuffer, (unsigned int *)&signatureLength, privateKey) == NO) {
NSLog(#"Failed to sign string.");
return nil;
}
EVP_MD_CTX_cleanup(&msgDigestContext);
EVP_PKEY_free(privateKey);
NSData *signatureData = [NSData dataWithBytes:signatureBuffer length:signatureLength];
NSString *signature = [signatureData base64EncodedStringWithOptions:0];
return signature;
}
#end
In the class that will be signing the string, you can now import NSString+openssl_sign.h and sign the string like so:
NSData *privateKey = ...; // Read the .pem file into a NSData variable
NSString *helloSignature = [#"hello" signStringWithPrivateKey:privateKey];
You can verify that the signatures are the same using the following command in Terminal:
echo -n "hello" | openssl dgst -sha1 -sign priv.pem | openssl enc -base64 | tr -d '\n'
You can solve this much easier with no external sources or components.
I found out how and wanted to share it so i may help others.
You need to load the key file a SecKeyRef and safe the maxPlainLen as well
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:privateKeyResourceName 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:#"_YOURPASSWORDHERE__" 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);
privateKey = privateKeyRef;
maxPlainLen = SecKeyGetBlockSize(privateKey) - 12;
You can convert NSString with a category method to SHA1
- (NSData*)toSha1AsData {
// PHP uses ASCII encoding, not UTF
const char *s = [self 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]
return out;
}
Now you can sign your SHA1 with this method
(NSData *)signSha1Data:(NSData *)data {
size_t plainLen = [data length];
if (plainLen > maxPlainLen)
{
NSLog(#"content(%ld) is too long, must < %ld", plainLen, maxPlainLen);
return nil;
}
void *plain = malloc(plainLen);
[data getBytes:plain
length:plainLen];
size_t cipherLen = 128; // currently RSA key length is set to 128 bytes
void *cipher = malloc(cipherLen);
OSStatus returnCode = SecKeyRawSign(privateKey, kSecPaddingPKCS1SHA1,
plain, plainLen, cipher, &cipherLen);
NSData *result = nil;
if (returnCode != 0) {
NSLog(#"SecKeyEncrypt fail. Error Code: %ld", returnCode);
}
else {
result = [NSData dataWithBytes:cipher
length:cipherLen];
}
free(plain);
free(cipher);
return result;
}
It works very well and without any external libs. There is no need to compile some wierd openssl stuff.

Resources