One function gives several results in swift - ios

I have a method in objective-C which I call from swift. It worked pretty well in swift 2, but in swift 3 the behaviour has changed. It gives me 3 different results, even though I send the same parameters.
Sometimes it doesnt find pfile, sometimes it fails on pin checking, sometimes works good and gives me x509.
char* ParsePKCS12(unsigned char* pkcs12_path, unsigned char * pin) {
printf("PARSE PATH: %s\n", pkcs12_path);
printf("PASSWORD: %s\n", pin);
NSString *pfile = [NSString stringWithUTF8String:pkcs12_path];
FILE *fp;
PKCS12 *p12;
EVP_PKEY *pkey;
X509 *cert;
BIO *databio = BIO_new(BIO_s_mem());
STACK_OF(X509) *ca = NULL;
if([[NSFileManager defaultManager] fileExistsAtPath:pfile]) {
NSLog(#"ok, pfile exists!");
} else {
NSLog(#"error, pfile does not exists!");
return "-1";
}
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
fp = fopen([pfile UTF8String], "rb");
p12 = d2i_PKCS12_fp(fp, NULL);
fclose (fp);
if (!p12) {
fprintf(stderr, "Error reading PKCS#12 file\n");
ERR_print_errors_fp(stderr);
return "-1";
}
if (!PKCS12_parse(p12, (const char *)pin, &pkey, &cert, &ca)) { //Error at parsing or pin error
fprintf(stderr, "Error parsing PKCS#12 file\n");
ERR_print_errors_fp(stderr);
ERR_print_errors(databio);
return "-1";
}
BIO *bio = NULL;
char *pem = NULL;
if (NULL == cert) {
//return NULL;
return "-1";
}
bio = BIO_new(BIO_s_mem());
if (NULL == bio) {
return "-1";
}
if (0 == PEM_write_bio_X509(bio, cert)) {
BIO_free(bio);
//return NULL;
}
pem = (char *) malloc(bio->num_write + 1);
if (NULL == pem) {
BIO_free(bio);
return "-1";
}
memset(pem, 0, bio->num_write + 1);
BIO_read(bio, pem, bio->num_write);
BIO_free(bio);
PKCS12_free(p12);
return pem;
}
this code I call in swift like this:
self.x509 = String(cString:ParsePKCS12(UnsafeMutablePointer<UInt8>(mutating: self.path),
UnsafeMutablePointer<UInt8>(mutating: "123456"))!)

Your call
self.x509 = String(cString:ParsePKCS12(UnsafeMutablePointer<UInt8>(mutating: self.path),
UnsafeMutablePointer<UInt8>(mutating: "123456"))!)
does not work reliably because in both
UnsafeMutablePointer<UInt8>(mutating: someSwiftString)
calls, the compiler creates a temporary C string representation of
the Swift string and passes that to the function. But that C string
is only valid until the UnsafeMutablePointer constructor returns, which means that the second
string conversion can overwrite the first, or any other undefined
behaviour.
The simplest solution would be to change the C function to
take constant C strings (and use the default signedness):
char* ParsePKCS12(const char * pkcs12_path, const char * pin)
Then you can simply call it as
self.x509 = String(cString: ParsePKCS12(self.path, "123456"))
and the compiler creates temporary C strings which are valid during
the call of ParsePKCS12().

Related

S/MIME email encryption library for iOS

I am trying to find a S/MIME email encryption library for an iOS email app I am creating in Swift. I have been having trouble trying to find a library for the encryption, has anyone had any experience with this?
I have tried OpenSSL but have run into issues with importing all the files in need in the bridging header, for example I need to use functions in pem.h but if I try import pem.h the bridging header fails to be imported altogether.
Any help with this would be greatly appreciated.
I had a similar requirement. Eventually I had to import openSSL and write my own code to handle the decrypt of PKCS7. I made a small github repo which should help
https://github.com/zkrige/iOS-pkcs7-decrypt
here is the gist of the code
#include <openssl/bio.h>
#include <openssl/cms.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/crypto.h>
#include <openssl/rand.h>
X509 *getCert(const char *certificate) {
BIO *membuf = BIO_new(BIO_s_mem());
BIO_puts(membuf, certificate);
X509 *x509 = PEM_read_bio_X509(membuf, NULL, NULL, NULL);
return x509;
}
EVP_PKEY *getKey(const char *privateKey) {
BIO *membuf = BIO_new(BIO_s_mem());
BIO_puts(membuf, privateKey);
EVP_PKEY *key = PEM_read_bio_PrivateKey(membuf, NULL, 0, NULL);
return key;
}
PKCS7 *getContainer(const char *encrypted) {
BIO* membuf = BIO_new(BIO_s_mem());
BIO_set_mem_eof_return(membuf, 0);
BIO_puts(membuf, encrypted);
PKCS7* pkcs7 = SMIME_read_PKCS7(membuf, NULL);
if (!pkcs7) {
fprintf(stderr, "error: %ld\n", ERR_get_error());
}
return pkcs7;
}
char *decrypt(PKCS7 *pkcs7, EVP_PKEY *pkey, X509 *cert) {
BIO *out = BIO_new(BIO_s_mem());
if (PKCS7_decrypt(pkcs7, pkey, cert, out, 0) != 1) {
X509_free(cert);
EVP_PKEY_free(pkey);
PKCS7_free(pkcs7);
fprintf(stderr, "Error decrypting PKCS#7 object: %ld\n", ERR_get_error());
return NULL;
}
BUF_MEM* mem;
BIO_get_mem_ptr(out, &mem);
char *data = malloc(mem->length + 1);
memcpy(data, mem->data, mem->length + 1);
BIO_flush(out);
BIO_free(out);
return data;
}
char *decrypt_smime(const char *encrypted, const char *privateKey, const char *certificate) {
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
X509 *cert = getCert(certificate);
if (!cert) {
return NULL;
}
EVP_PKEY *pkey = getKey(privateKey);
if (!pkey) {
X509_free(cert);
return NULL;
}
PKCS7 *pkcs7 = getContainer(encrypted);
if (!pkcs7) {
X509_free(cert);
EVP_PKEY_free(pkey);
return NULL;
}
char *data = decrypt(pkcs7, pkey, cert);
X509_free(cert);
EVP_PKEY_free(pkey);
PKCS7_free(pkcs7);
return data;
}

Memory Leak in C and C++ Code

I am trying to return a pointer from a function and use the return in a different function but I am getting memory leak.
The test code which I wrote and detected with memory leak by CPPCheck.
########################################################################
# include < stdio.h >
# include < malloc.h >
# include < string.h >
char* replace ( char* st, char* word, char *replaceWith );
int main ( void )
{
char str[] = "Hello how are ## and what are ## doing ?";
char word[]="##";
char replaceWith[]="you";
printf("%s",replace(str,word,replaceWith));
getchar();
return 0;
}
char* replace(char* st,char* word,char *replaceWith)
{
int i = 0;
char *sr,*s,*ret;
int oldlen;
int count = 0;
int newlen;
int stlen;
s=(char *)malloc(strlen(st) + 1);
strcpy(s, st);
oldlen=strlen(word);
newlen=strlen(replaceWith);
for (i = 0; s[i]! = '\0'; )
{
if( memcmp( &s[i], word, oldlen ) == 0)
{
count++;
i+=oldlen;
}
else
{
i++;
}
}
sr= (char *) malloc (i+1+count*(newlen-oldlen));
ret = (char *) malloc (i+1+count*(newlen-oldlen));
ret=sr;
while(*s)
{
if(memcmp( s, word, oldlen) == 0)
{
memcpy(sr, replaceWith, newlen);
s+ = oldlen;
sr+ = newlen;
}
else
{
*sr++ = *s++;
}
}
*sr = '\0';
return ret;
}
Try this
#include<stdio.h>
#include<malloc.h>
#include<string.h>
char* replace ( char* st, char* word, char *replaceWith );
int main ( void )
{
char str[] = "Hello how are ## and what are ## doing ?";
char word[]="##";
char replaceWith[]="you";
char * ret = replace(str,word,replaceWith);
printf("%s",ret);
free(ret); //freeing the allocated memory
getchar();
return 0;
}
char* replace(char* st,char* word,char *replaceWith)
{
int i = 0;
char *sr,*s,*ret, *temps;
int oldlen;
int count = 0;
int newlen;
int stlen;
s=(char *)malloc(strlen(st) + 1);
temps = s; // storing the address of s in a temp location
strcpy(s, st);
oldlen=strlen(word);
newlen=strlen(replaceWith);
for (i = 0; s[i]!= '\0';)
{
if( memcmp( &s[i], word, oldlen ) == 0)
{
count++;
i+=oldlen;
}
else
{
i++;
}
}
sr= (char *) malloc (i+1+count*(newlen-oldlen));
ret=sr;
while(*s)
{
if(memcmp( s, word, oldlen) == 0)
{
memcpy(sr, replaceWith, newlen);
s += oldlen;
sr += newlen;
}
else
{
*sr++ = *s++;
}
}
*sr = '\0';
free(temps); // freeing the memory allocated for s
return ret;
}
Always free same count with malloc.
free s, sr at end of replace,
use return value of replace instead of direct use on printf
and free return value (return of ret from replace) when not needed.
I have doing lots of experimenting with the memory leak and meanwhile I wrote the following code. Please comment about the pros and cons side of it.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
// Prototype declaration of replaceAll function
static char* replaceAll(char *pSource, char *pWord, char*pWith);
/////////////////////////////////////////////////////////////////////////////
//
// NAME : main
//
// DESCRIPTION : Implementation of main which invokes the replaceAll
// function and displays the output
//
// PARAMETERS : void
//
// RETURNED VALUE : int
//
/////////////////////////////////////////////////////////////////////////////
int main( void )
{
char *finalString = NULL; // To save the base returned address
char srcString[] = "Hello how r you"; // Actual String
char pWord[] = "r"; // Word to be replaced
char pWith[] = "are"; // Word to be replaced with
printf("\n Before Calling the replaceAll function:");
printf("%s",srcString);
printf("\n");
finalString = replaceAll(srcString, pWord, pWith); //calling the replaceAll function
printf("\n After Calling the replaceAll function:");
// Checking if NULL is returned
if( finalString != NULL )
{
//printing the string
printf("%s", finalString);
}
else
{
printf("\n Error: Blank String returned ");
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
//
// NAME : replaceAll
//
// DESCRIPTION : Implementation of replaceAll function which replaces
// a word in given string with another word
//
// PARAMETERS : char *
//
// RETURNED VALUE : char *
//
/////////////////////////////////////////////////////////////////////////////
static char* replaceAll(char *pSource, char *pWord, char*pWith)
{
char *pSt = NULL; // Pointer to the source String to avoid modifying the pSource
char *pTarget = NULL; // Target pointer to be malloced
char *pTg = NULL; // Pointer to the target string
int count; // Counter
int nWord = strlen (pWord); // length of the word which needs to be replaced
int nWith = strlen (pWith); // length of the word with which the word needs to be replaced
static const char nullP = '\0'; // null character
int szTarget = 0;
// Assigning the base address of the pSource to a temporary and iterate through
for ( pSt = pSource, count = 0; *pSt != nullP; pSt++ )
{
// Count number of occurances of the Word in the String to calculate the length of the final string
if( memcmp( pSt, pWord, nWord ) == 0)
{
count++;
pSt += nWord-1;
}
}
// Calculate the required target Size
szTarget = strlen (pSource) + count * (nWith - nWord) + sizeof (nullP);
// Allocate memory for the target string
pTarget = (char *)malloc(szTarget);
// Check if the malloc function returns sucessfully
if ( pTarget != NULL)
{
// Copying the string with replacement
for (pTg = pTarget, pSt = pSource; *pSt != nullP; )
{
if( memcmp (pSt, pWord, nWord) == 0)
{
memcpy (pTg,pWith,nWith);
pSt += nWord;
pTg += nWith;
}
else
{
*pTg++ = *pSt++;
}
}
// Assigning NULL Character to the target string after copying
*pTg = '\0';
}
return pTarget;
}

The base64 encode formatted output from Arduino HMAC-SHA1 does not match with JAVA/python/online tool

I am working on an Arduino project which is required an authorized authentication based on OAuth 1.0 to connects to the cloud. This is alike [Authorizing a request to Twitter API][1], and I am stuck in the step of [Creating a signature][2]. The whole process of creating a signature requires algorithms like encodeURL, base64encode, and hmac-sha1. On my Arduino project, I use Cryptosuite(link 3) library for hmac-sha1 and arduino-base64(link 4) library for base64encode. Both of them are working fine separately. However, I need to get a base64-formatted output of hmac-sha1. So I have tried this:
#include <avr/pgmspace.h>
#include <sha1.h>
#include <Base64.h>
uint8_t *in, out, i;
char b64[29];
static const char PROGMEM b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char key[] = "testKey";
char basestring[] = "testing";
void printHash(uint8_t* hash) {
int i;
for (i=0; i<20; i++) {
Serial.print("0123456789abcdef"[hash[i]>>4]);
Serial.print("0123456789abcdef"[hash[i]&0xf]);
}
Serial.println();
}
void setup() {
Serial.begin(115200);
Serial.print("Result:");
Sha1.initHmac((uint8_t*)key, strlen(key));
Sha1.print(basestring);
printHash(Sha1.resultHmac());
Serial.println();
// encoding
char* input;
input = (char*)(Sha1.resultHmac());
int inputLen = strlen(input);
int encodedLen = base64_enc_len(inputLen);
char encoded[encodedLen];
// note input is consumed in this step: it will be empty afterwards
base64_encode(encoded, input, inputLen);
Serial.print("base64 result: ");
Serial.println(encoded);
}
void loop() {
}
The output of printHash that I got is 60d41271d43b875b791e2d54c34bf3f018a29763, which is exactly same with the online verification tool(link 5).
However, I supposed to get YNQScdQ7h1t5Hi1Uw0vz8Biil2M= for the base64 result. But I got L18B0HicKRhuxmB6SIFpZP+DpHxU which seems wrong. I have also tried to write a JAVA program and a python program, which also said that the output of the base64 result should be YNQScdQ7h1t5Hi1Uw0vz8Biil2M=
I also found this post: Issues talking between Arduino SHA1-HMAC and base64 encoding and Python(link 6). I have also tried the tidy function it mentioned from Adafruit-Tweet-Receipt(link 7).
// base64-encode SHA-1 hash output. This is NOT a general-purpose base64
// encoder! It's stripped down for the fixed-length hash -- always 20
// bytes input, always 27 chars output + '='.
for(in = Sha1.resultHmac(), out=0; ; in += 3) { // octets to sextets
b64[out++] = in[0] >> 2;
b64[out++] = ((in[0] & 0x03) << 4) | (in[1] >> 4);
if(out >= 26) break;
b64[out++] = ((in[1] & 0x0f) << 2) | (in[2] >> 6);
b64[out++] = in[2] & 0x3f;
}
b64[out] = (in[1] & 0x0f) << 2;
// Remap sextets to base64 ASCII chars
for(i=0; i<=out; i++) b64[i] = pgm_read_byte(&b64chars[b64[i]]);
b64[i++] = '=';
b64[i++] = 0;
Is there any mistake I've made in here?
Thanks!
So full example will be:
#include <avr/pgmspace.h>
#include <sha1.h>
#include <Base64.h>
char key[] = "testKey";
char basestring[] = "testing";
void printHash(uint8_t* hash) {
for (int i=0; i<20; i++) {
Serial.print("0123456789abcdef"[hash[i]>>4]);
Serial.print("0123456789abcdef"[hash[i]&0xf]);
}
Serial.println();
}
void setup() {
Serial.begin(115200);
Serial.print("Input: ");
Serial.println(basestring);
Serial.print("Key: ");
Serial.println(key);
Serial.print("Hmac-sha1 (hex): ");
Sha1.initHmac((uint8_t*)key, strlen(key));
Sha1.print(basestring);
uint8_t *hash;
hash = Sha1.resultHmac();
printHash(hash);
// base64 encoding
char* input = (char*) hash;
int inputLen = strlen(input) - 1; // skip null termination
int encodedLen = base64_enc_len(inputLen);
char encoded[encodedLen];
// note input is consumed in this step: it will be empty afterwards
base64_encode(encoded, input, inputLen);
Serial.print("Hmac-sha1 (base64): ");
Serial.println(encoded);
}
void loop() { }
which outputs:
Input: testing
Key: testKey
Hmac-sha1 (hex): 60d41271d43b875b791e2d54c34bf3f018a29763
Hmac-sha1 (base64): YNQScdQ7h1t5Hi1Uw0vz8Biil2M=

Using fgets and strtok to read in data and create linked list

Need some help with reading in lines of data from a text file using the fgets and string tokenization commands, which will then be used to create a linked list. I've followed some examples I've found on Stack Overflow and other tutorial websites, but still cannot get the read function below to work properly in my program, it just causes it to crash. The data file has lines like this:
Zucchini, Squash, pound, 2.19, 45
Yellow, Squash, pound, 1.79, 15
Based on everything I've read, I believe I have the necessary code, but obviously I'm missing something. Also, I commented out one of the fields (the one for float price) as I'm not sure what to use to copy the float value from the data, as I cannot treat it as a string (the integer value right below it seems to let me get away with it in my compiler).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Struct for linked list node
struct produceItem
{
char produce[20];
char type[20];
char soldBy[20];
float price;
int quantityInStock;
struct produceItem *next;
};
// Function to read in data from file to
void read(struct produceItem **head)
{
struct produceItem *temp = NULL;
struct produceItem *right = NULL;
//char ch[3];
char line[50];
char *value;
FILE *data = fopen("RecitationFiveInput.txt", "r");
printf("Trying to open file RecitationFiveInput.txt\n");
if (data == NULL)
{
printf("Could not open file RecitationFiveInput.txt\n");
}
else
{
while(fgets(line, sizeof(line), data))
{
value = strtok(line, ", ");
strcpy(temp->produce, strdup(value));
value = strtok(NULL, ", ");
strcpy(temp->type, strdup(value));
value = strtok(NULL, ", ");
strcpy(temp->soldBy, strdup(value));
//value = strtok(NULL, ", ");
//strcpy(temp->price, strdup(value));
value = strtok(NULL, " \n");
strcpy(temp->quantityInStock, strdup(value));
temp->next = NULL;
if (*head == NULL)
{
*head = temp;
}
else
{
right = *head;
while(right->next != NULL)
{
right = right->next;
}
right->next = temp;
}
}
printf("Successfully opened file RecitationFiveInput.txt\n");
}
fclose(data);
return;
}
// Function to display the nodes of the linked list that contains the data from the data file
void display(struct produceItem *head)
{
int value = 1;
struct produceItem *temp = NULL;
temp = head;
printf("=============================================================================\n");
printf(" Item # Produce Type Sold By Price In Stock\n");
printf("=============================================================================\n");
if(temp == NULL)
{
return;
}
else
{
while(temp != NULL)
{
printf(" %d %s %s %s %lf %d\n", value, temp->produce, temp->type, temp->soldBy, temp->price, temp->quantityInStock);
value++;
temp = temp->next;
if(temp == NULL)
{
break;
}
}
}
return;
}
//Main function
int main()
{
int input = 0;
struct produceItem *head = NULL;
while(1)
{
printf("\nList Operations\n");
printf("=================\n");
printf("1. Stock Produce Department\n");
printf("2. Display Produce Inventory\n");
printf("3. Reverse Order of Produce Inventory\n");
printf("4. Export Produce Inventory\n");
printf("5. Exit Program\n");
printf("Enter your choice: ");
if(scanf("%d", &input) <= 0)
{
printf("Enter only an integer.\n");
exit(0);
}
else
{
switch(input)
{
case 1:
read(&head);
break;
case 2:
display(head);
break;
case 3:
//function
break;
case 4:
//function
break;
case 5:
printf("You have exited the program, Goodbye!\n");
return 0;
break;
default:
printf("Invalid option.\n");
}
}
}
return 0;
}
Never mind everyone, found the issue. The crashes were due to me not allocating memory for the temp pointer in the read me function.

Import PEM encoded X.509 certificate into iOS KeyChain

I'm receiving a String containing a PEM encoded X.509 certificate from somewhere. I'd like to import this certificate into the KeyChain of iOS.
I'm planning to do the following:
convert NSString to openssl X509
create PKCS12
convert PKCS12 to NSData
import NSData with SecPKCS12Import
So far I came up with the following code:
const char *cert_chars = [certStr cStringUsingEncoding:NSUTF8StringEncoding];
BIO *buffer = BIO_new(BIO_s_mem());
BIO_puts(buffer, cert_chars);
X509 *cert;
cert = PEM_read_bio_X509(buffer, NULL, 0, NULL);
if (cert == NULL) {
NSLog(#"error");
}
X509_print_fp(stdout, cert);
EVP_PKEY *privateKey;
const unsigned char *privateBits = (unsigned char *) [privateKeyData bytes];
int privateLength = [privateKeyData length];
privateKey = d2i_AutoPrivateKey(NULL, &privateBits, privateLength);
if (!X509_check_private_key(cert, privateKey)) {
NSLog(#"PK error");
}
PKCS12 *p12 = PKCS12_create("test", "David's Cert", privateKey, cert, NULL, 0, 0, 0, 0, 0);
Unfortunately, p12 is nil even though X509_check_private_key was successful and X509_print_fp(stdout, cert) prints a valid certificate.
is my approach correct
how come PKCS12_create seems to fail?
Update:
The call PKCS12_create seems to fail in the following method:
int EVP_PBE_CipherInit(ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de)
{
const EVP_CIPHER *cipher;
const EVP_MD *md;
int cipher_nid, md_nid;
EVP_PBE_KEYGEN *keygen;
if (!EVP_PBE_find(EVP_PBE_TYPE_OUTER, OBJ_obj2nid(pbe_obj),
&cipher_nid, &md_nid, &keygen))
{
char obj_tmp[80];
EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_UNKNOWN_PBE_ALGORITHM);
if (!pbe_obj) BUF_strlcpy (obj_tmp, "NULL", sizeof obj_tmp);
else i2t_ASN1_OBJECT(obj_tmp, sizeof obj_tmp, pbe_obj);
ERR_add_error_data(2, "TYPE=", obj_tmp);
return 0;
}
if(!pass)
passlen = 0;
else if (passlen == -1)
passlen = strlen(pass);
if (cipher_nid == -1)
cipher = NULL;
else
{
cipher = EVP_get_cipherbynid(cipher_nid);
if (!cipher)
{
EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_UNKNOWN_CIPHER);
return 0;
}
}
if (md_nid == -1)
md = NULL;
else
{
md = EVP_get_digestbynid(md_nid);
if (!md)
{
EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_UNKNOWN_DIGEST);
return 0;
}
}
if (!keygen(ctx, pass, passlen, param, cipher, md, en_de))
{
EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_KEYGEN_FAILURE);
return 0;
}
return 1;
}
Retrieving the cipher
cipher = EVP_get_cipherbynid(cipher_nid);
somehow returns nil for "RC2-40-CBC".
The following calls were missing before creating the PKCS12:
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
These solved the problems with the missing cipher and also a subsequent problem of a missing digest.

Resources