Hello i am using this library for implementation of annotation but facing one issue of attachment of image it provide PdfFileSpec objective c++ function i tried to convert this function to objective c but getting error in below image
class PODOFO_DOC_API PdfFileSpec : public PdfElement {
public:
PdfFileSpec( const char* pszFilename, bool bEmbedd, PdfDocument* pParent );
PdfFileSpec( const char* pszFilename, bool bEmbedd, PdfVecObjects* pParent );
/* Petr P. Petrov 17 September 2009*/
/** Embeds the file in memory from "data" buffer under "pszFileName" fie name.
*/
PdfFileSpec( const char* pszFilename, const unsigned char* data, ptrdiff_t size, PdfVecObjects* pParent);
PdfFileSpec( PdfObject* pObject );
/** \returns the filename of this file specification.
* if no general name is available
* it will try the Unix, Mac and DOS keys too.
*/
const PdfString & GetFilename() const;
+(void)createFreeTextAnnotationOnPage:(NSInteger)pageIndex doc:(PdfMemDocument*)aDoc rect:(CGRect)aRect borderWidth:(double)bWidth title:(NSString*)title content:(NSString*)content bOpen:(Boolean)bOpen color:(UIColor*)color {
PoDoFo::PdfMemDocument *doc = (PoDoFo::PdfMemDocument *) aDoc;
PoDoFo::PdfPage* pPage = doc->GetPage(pageIndex);
if (! pPage) {
// couldn't get that page
return;
}
PoDoFo::PdfAnnotation* anno;
PoDoFo::EPdfAnnotation type= PoDoFo::ePdfAnnotation_Text;
PoDoFo::PdfRect rect;
rect.SetBottom(aRect.origin.y);
rect.SetLeft(aRect.origin.x);
rect.SetHeight(aRect.size.height);
rect.SetWidth(aRect.size.width);
NSData *data=UIImagePNGRepresentation([UIImage imageNamed:#"Add_button.png"]);
anno = pPage->CreateAnnotation(type , rect);
NSString *myString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
PoDoFo::PdfString sTitle([title UTF8String]);
PoDoFo::PdfString sContent([content UTF8String]);
PoDoFo::PdfFileSpec data1([myString UTF8String], true, doc);
}
I don't see why you are using reinterpret_cast, and it's certainly being misused in the construction of data1.
Have you simply tried:
PoDoFo::PdfString sTitle([title UTF8String]);
PoDoFo::PdfString sContent([content UTF8String]);
PoDoFo::PdfFileSpec data1([myString UTF8String], true, doc);
Related
I'm trying to RSA encrypt an NSData using a public key. The public key is in this format:
<RSAKeyValue>
<Modulus>yOTe0L1/NcbXdZYwliS82MiTE8VD5WD23S4RDsdbJOFzCLbsyb4d+K1M5fC+xDfCkji1zQjPiiiToZ7JSj/2ww==</Modulus>
<Exponent>AWAB</Exponent>
</RSAKeyValue>
After extracting the modulus and exponent from the XML string, how do I get a SecKeyRef out of those to be used as publicKey in the method below?
+ (NSString *)encryptRSA:(NSString *)plainTextString key:(SecKeyRef)publicKey
{
size_t cipherBufferSize = SecKeyGetBlockSize(publicKey);
uint8_t *cipherBuffer = malloc(cipherBufferSize);
uint8_t *nonce = (uint8_t *)[plainTextString UTF8String];
SecKeyEncrypt(publicKey,
kSecPaddingOAEP,
nonce,
strlen( (char*)nonce ),
&cipherBuffer[0],
&cipherBufferSize);
NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize];
return [encryptedData base64EncodedString];
}
I can't seem to find a definite answer anywhere.
Wow, no wonder it's so hard to find an answer to this. I spent 2 days down the crypto-rabbit hole, and it's not pretty.
The easy way
Use Chilkat iOS RSA Library. One major downside: cost $189! :O
The hard way
Parse the XML, use SCZ-BasicEncodingRules-iOS to generate a public key data out of the modulus and exponent. If that works, create a dummy keychain using that public key (follow sample code here), extract the public key now in SecKeyRef format and pass it to the encryptRSA method in the question. Finally, cleanup, remove the dummy keychain. Sounds good in theory, but I have never tested this thoroughly, if you do, let me know!
I have used the below method for encryption using public key without using any third party libs, guess it may help who is looking for the same after they implemented it just as I did :D
+(NSString *)encryptRSA:(NSString *)plainTextString key:(SecKeyRef)publicKey
{
size_t cipherBufferSize = SecKeyGetBlockSize(publicKey);
uint8_t *cipherBuffer = malloc(cipherBufferSize);
uint8_t *nonce = (uint8_t *)[plainTextString UTF8String];
SecKeyEncrypt(publicKey,
kSecPaddingPKCS1,
nonce,
strlen( (char*)nonce ),
&cipherBuffer[0],
&cipherBufferSize);
NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize];
return [encryptedData base64EncodedStringWithOptions:0];
}
I think this will help u!
you can create a java file like fellow:
this java funtion will generate a public key to base64String
public static RSAPublicKey getPublicKey(String modulus, String exponent) {
try {
BigInteger b1 = new BigInteger(modulus,16);
BigInteger b2 = new BigInteger(exponent,16);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String encodePublicKey(byte[] encoded) throws Exception{
BASE64Encoder base64Encoder= new BASE64Encoder();
String s=base64Encoder.encode(encoded);
return s;
u should use like :encodePublicKey(publicKey.getEncoded());
Got it!
I have this sqlite3 table used in an iOS 6 app for iPad:
CREATE TABLE notes(id INTEGER PRIMARY KEY, note TEXT, noteDate TEXT, wasUploaded INTEGER);
from the sqlite3 command line this query works:
sqlite> Select `id`,`note`,`noteDate`,`wasUploaded` FROM `notes` WHERE `wasUploaded`=0;
1|Well|2012-10-04 22:46:23|0
On iOS iPad 6.0 Simulator each of these queries returns the exact same data as above:
const char *sqlStatement = "Select `id`,`note`,`noteDate`,`wasUploaded` FROM `notes` WHERE `id`=1";
const char *sqlStatement = "Select `id`,`note`,`noteDate`,`wasUploaded` FROM `notes` WHERE `note`='Well'";
const char *sqlStatement = "Select `id`,`note`,`noteDate`,`wasUploaded` FROM `notes` WHERE `noteDate`='2012-10-04 22:46:23'";
But this query which worked fine on the command line now returns no data:
const char *sqlStatement = "Select `id`,`note`,`noteDate`,`wasUploaded` FROM `notes` WHERE `wasUploaded`=0";
Has me baffled. Why is that last query not working? Do I need to make that column an index or something? The other two non-indexed columns work but not this.
No errors. The last query that returns no data gives a normal return code of 101 (sqlite3_step() has finished executing) and a query without the where clause returns the same data as for the other three queries.
Edit: here is the complete code
- (NSString *)getNotesToBeUploaded {
sqlite3 *stuDb;
NSString *thisNote;
NSMutableString *notes = [[NSMutableString alloc]init];
if (self.filePath == #"empty") {
[self setDatabaseFilePath];
}
if (sqlite3_open([self.filePath UTF8String], &stuDb) == SQLITE_OK)
{
// this is the query line that get changed to show stackoverflow the different results:
const char *sqlStatement = "Select `id`,`note`,`noteDate` FROM notes WHERE `wasUploaded`=0";
sqlite3_stmt *compiledStatement;
int nResult = sqlite3_prepare_v2(stuDb, sqlStatement, -1, &compiledStatement, NULL);
if ( nResult == SQLITE_OK)
{
int nret; // diagnostic used to watch return vaues when single stepping
while ((nret = sqlite3_step(compiledStatement)) == SQLITE_ROW)
{
int id = sqlite3_column_int(compiledStatement, 0);
const unsigned char *note = sqlite3_column_text(compiledStatement, 1);
const unsigned char *noteDate = sqlite3_column_text(compiledStatement, 2);
int wu = sqlite3_column_int(compiledStatement, 4);
if (strlen((const char *)note) > 0 && strlen((const char *)noteDate) > 0)
{
thisNote = [NSString stringWithFormat:#"%d,%s,%s,%d\n",id, noteDate, note, wu];
[notes appendString:thisNote];
}
}
} else {
sqlite3_finalize(compiledStatement);// prevent small memory leaks
sqlite3_close(stuDb);
thisNote =
[NSString stringWithFormat:#"prepare failed with status:%d in %s at line %d path was %#,0,0\n",nResult,__FILE__,__LINE__,self.filePath];
[notes appendString:thisNote];
[notes appendString:#"\n"];
return (NSString *)notes;
}
sqlite3_finalize(compiledStatement);
sqlite3_close(stuDb);
}
Are you checking the return codes from your sqlite3 calls? And, if you're not getting SQLITE_OK or SQLITE_ROW, as appropriate, you should check the sqlite3_errmsg results to diagnose what's going on. You really should share your code if you want us to help you.
But the most common problems in the first-time iOS SQLite apps are
Failing to include the database in your app's bundle. Check your Target settings and make sure you've included the database in the Build Phases. You can also confirm this by looking at your app's bundle in the simulator in the ~/Library/Application Support/iPhone Simulator folder. If you want to do that, you may want to unhide your ~/Library folder if you haven't by typing in chflags no hidden ~/Library in the Terminal command line interface.
If you're planning on updating your database from the app, failing to first copy the database from the bundle to the Documents folder before you try to start using it.
Using sqlite3_open and interpreting a successful return code as evidence that the database was opened successfully ... but if it didn't find the database, the sqlite3_open function annoyingly will create a new blank database ... I always suggest that people use sqlite3_open_v2 instead, in which you can omit the parameter to create a blank database if it's not found if that's not what you want.
Certainly, there can be a ton of code-related issues (order that the functions are called, failing to check return codes, etc.), too. It's impossible to comment further without seeing the code.
And I feel obliged to share my final SQLite programming advice that it's worth checking out FMDB Objective-C SQLite wrapper library, which greatly simplifies SQLite programming in iOS.
Update:
Having looked at your code, it looks fine. I just ran it (only tweaked to just NSLog rather than appending notes):
- (void)test2
{
sqlite3 *stuDb;
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *databaseName = [documentsDirectory stringByAppendingPathComponent:#"test.db"];
if (sqlite3_open([databaseName UTF8String], &stuDb) == SQLITE_OK)
{
// this is the query line that get changed to show stackoverflow the different results:
const char *sqlStatement = "Select `id`,`note`,`noteDate` FROM notes WHERE `wasUploaded`=0";
sqlite3_stmt *compiledStatement;
int nResult = sqlite3_prepare_v2(stuDb, sqlStatement, -1, &compiledStatement, NULL);
if ( nResult == SQLITE_OK)
{
int nret; // diagnostic used to watch return vaues when single stepping
while ((nret = sqlite3_step(compiledStatement)) == SQLITE_ROW)
{
int id = sqlite3_column_int(compiledStatement, 0);
const unsigned char *note = sqlite3_column_text(compiledStatement, 1);
const unsigned char *noteDate = sqlite3_column_text(compiledStatement, 2);
int wu = sqlite3_column_int(compiledStatement, 4);
if (strlen((const char *)note) > 0 && strlen((const char *)noteDate) > 0)
{
// thisNote = [NSString stringWithFormat:#"%d,%s,%s,%d\n",id, noteDate, note, wu];
// [notes appendString:thisNote];
NSLog(#"%d,%s,%s,%d\n",id, noteDate, note, wu);
}
}
} else {
//sqlite3_finalize(compiledStatement);// prevent small memory leaks, not needed if the prepare failed
sqlite3_close(stuDb);
NSLog(#"prepare failed with error %s", sqlite3_errmsg(stuDb));
return;
}
sqlite3_finalize(compiledStatement);
sqlite3_close(stuDb);
}
}
And I got results:
2012-10-05 15:44:06.075 test8[1574:c07] 1,2012-10-05 19:43:37,ABC,0
2012-10-05 15:44:06.076 test8[1574:c07] 2,2012-10-05 19:43:46,XYZ,0
So the problem must be in the database itself. Judging from your last comment, it sounds like rebuilding the database did it for you. That's great.
I have a certificate (SecCertificateRef), I can check if it's valid and I can extract a "summary" using SecCertificateCopySubjectSummary.
What is the "summary" exactly? I don't understand the term "A string that contains a human-readable summary of the contents of the certificate." in the Apple documentation. I think, they mean the "CN" in the certificate, correct?
Is there any method to get the clear X509-information out of SecCertificateRef? Does a cast to a keychain-object help?
I want to have something like this and I am especially focussed on the "CN" to compare it with the URL I submitted to avoid man-in-the-middle attacks. (Or any better ideas?)
That is what I want to have:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=XY, ST=Austria, L=Graz, O=TrustMe Ltd, OU=Certificate Authority, CN=CA/Email=ca#trustme.dom
Validity
Not Before: Oct 29 17:39:10 2000 GMT
Not After : Oct 29 17:39:10 2001 GMT
Subject: C=DE, ST=Austria, L=Vienna, O=Home, OU=Web Lab, CN=anywhere.com/Email=xyz#anywhere.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:c4:40:4c:6e:14:1b:61:36:84:24:b2:61:c0:b5:
d7:e4:7a:a5:4b:94:ef:d9:5e:43:7f:c1:64:80:fd:
9f:50:41:6b:70:73:80:48:90:f3:58:bf:f0:4c:b9:
90:32:81:59:18:16:3f:19:f4:5f:11:68:36:85:f6:
1c:a9:af:fa:a9:a8:7b:44:85:79:b5:f1:20:d3:25:
7d:1c:de:68:15:0c:b6:bc:59:46:0a:d8:99:4e:07:
50:0a:5d:83:61:d4:db:c9:7d:c3:2e:eb:0a:8f:62:
8f:7e:00:e1:37:67:3f:36:d5:04:38:44:44:77:e9:
f0:b4:95:f5:f9:34:9f:f8:43
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
email:xyz#anywhere.com
Netscape Comment:
mod_ssl generated test server certificate
Netscape Cert Type:
SSL Server
Signature Algorithm: md5WithRSAEncryption
12:ed:f7:b3:5e:a0:93:3f:a0:1d:60:cb:47:19:7d:15:59:9b:
3b:2c:a8:a3:6a:03:43:d0:85:d3:86:86:2f:e3:aa:79:39:e7:
82:20:ed:f4:11:85:a3:41:5e:5c:8d:36:a2:71:b6:6a:08:f9:
cc:1e:da:c4:78:05:75:8f:9b:10:f0:15:f0:9e:67:a0:4e:a1:
4d:3f:16:4c:9b:19:56:6a:f2:af:89:54:52:4a:06:34:42:0d:
d5:40:25:6b:b0:c0:a2:03:18:cd:d1:07:20:b6:e5:c5:1e:21:
44:e7:c5:09:d2:d5:94:9d:6c:13:07:2f:3b:7c:4c:64:90:bf:
ff:8e
I couldn't wait for an answer to the bounty, so I found a solution myself. As others said, Security.framework doesn't give you a way to get this information, so you need to ask OpenSSL to parse the certificate data for you:
#import <openssl/x509.h>
// ...
NSData *certificateData = (NSData *) SecCertificateCopyData(certificate);
const unsigned char *certificateDataBytes = (const unsigned char *)[certificateData bytes];
X509 *certificateX509 = d2i_X509(NULL, &certificateDataBytes, [certificateData length]);
NSString *issuer = CertificateGetIssuerName(certificateX509);
NSDate *expiryDate = CertificateGetExpiryDate(certificateX509);
Where CertificateGetIssuerName and CertificateGetExpiryDate are as follows:
static NSString * CertificateGetIssuerName(X509 *certificateX509)
{
NSString *issuer = nil;
if (certificateX509 != NULL) {
X509_NAME *issuerX509Name = X509_get_issuer_name(certificateX509);
if (issuerX509Name != NULL) {
int nid = OBJ_txt2nid("O"); // organization
int index = X509_NAME_get_index_by_NID(issuerX509Name, nid, -1);
X509_NAME_ENTRY *issuerNameEntry = X509_NAME_get_entry(issuerX509Name, index);
if (issuerNameEntry) {
ASN1_STRING *issuerNameASN1 = X509_NAME_ENTRY_get_data(issuerNameEntry);
if (issuerNameASN1 != NULL) {
unsigned char *issuerName = ASN1_STRING_data(issuerNameASN1);
issuer = [NSString stringWithUTF8String:(char *)issuerName];
}
}
}
}
return issuer;
}
static NSDate *CertificateGetExpiryDate(X509 *certificateX509)
{
NSDate *expiryDate = nil;
if (certificateX509 != NULL) {
ASN1_TIME *certificateExpiryASN1 = X509_get_notAfter(certificateX509);
if (certificateExpiryASN1 != NULL) {
ASN1_GENERALIZEDTIME *certificateExpiryASN1Generalized = ASN1_TIME_to_generalizedtime(certificateExpiryASN1, NULL);
if (certificateExpiryASN1Generalized != NULL) {
unsigned char *certificateExpiryData = ASN1_STRING_data(certificateExpiryASN1Generalized);
// ASN1 generalized times look like this: "20131114230046Z"
// format: YYYYMMDDHHMMSS
// indices: 01234567890123
// 1111
// There are other formats (e.g. specifying partial seconds or
// time zones) but this is good enough for our purposes since
// we only use the date and not the time.
//
// (Source: http://www.obj-sys.com/asn1tutorial/node14.html)
NSString *expiryTimeStr = [NSString stringWithUTF8String:(char *)certificateExpiryData];
NSDateComponents *expiryDateComponents = [[NSDateComponents alloc] init];
expiryDateComponents.year = [[expiryTimeStr substringWithRange:NSMakeRange(0, 4)] intValue];
expiryDateComponents.month = [[expiryTimeStr substringWithRange:NSMakeRange(4, 2)] intValue];
expiryDateComponents.day = [[expiryTimeStr substringWithRange:NSMakeRange(6, 2)] intValue];
expiryDateComponents.hour = [[expiryTimeStr substringWithRange:NSMakeRange(8, 2)] intValue];
expiryDateComponents.minute = [[expiryTimeStr substringWithRange:NSMakeRange(10, 2)] intValue];
expiryDateComponents.second = [[expiryTimeStr substringWithRange:NSMakeRange(12, 2)] intValue];
NSCalendar *calendar = [NSCalendar currentCalendar];
expiryDate = [calendar dateFromComponents:expiryDateComponents];
[expiryDateComponents release];
}
}
}
return expiryDate;
}
I only actually needed the issuer's organization name and the expiry date for my purposes, so that's all the code I've included below. But, based on this you should be able to figure out the rest by reading the x509.h header file.
Edit:
Here's how to get the certificate. I haven't put any error handling, etc. You'll want to check trustResult, err, etc., for example.
NSURLAuthenticationChallenge *challenge;
SecTrustResultType trustResult;
SecTrustRef trust = challenge.protectionSpace.serverTrust;
OSStatus err = SecTrustEvaluate(trust, &trustResult);
SecCertificateRef certificate = SecGetLeafCertificate(trust); // See Apple docs for implementation of SecGetLeafCertificate
better just use SecCertificateCopyCommonName to get CN to compare to your required hostname.
You were right Michael, iOS won't give you the API to do a full job on a X.509 certificates. Thankfully it will give you access to the actual (ASN.1) encoded certificate data. From there you can do your own decoding (not much fun) or delegate it to an existing library, like you did with OpenSSL.
Here's my version that uses the .NET framework. It's mean to be used by MonoTouch developers (and MonoMac developers too) who needs to interoperate with SecCertificateRef within their applications.
public void Show (SecCertificate sc)
{
// get the SecCertificate "raw", i.e. ASN.1 encoded, data
byte[] data = sc.DerData.ToArray<byte> ();
// the build the managed X509Certificate2 from it
X509Certificate2 cer = new X509Certificate2 (data);
// to get all properties / methods available in .NET (pretty exhaustive)
Console.WriteLine ("SubjectName: {0}", cer.Subject);
Console.WriteLine ("IssuerName: {0}", cer.Issuer);
Console.WriteLine ("NotBefore: {0}", cer.NotBefore);
Console.WriteLine ("NotAfter: {0}", cer.NotAfter);
Console.WriteLine ("SerialNumber: {0}", cer.SerialNumber);
// ...
}
If for some reason you want to do this without OpenSSL one can use the apple extraction keys. The first one will extract (just) the Subject and Issuer (there are more kSecOIDX509's for most other things, like expiry dates) and pass them for printing.
+(NSString*)stringFromCerificateWithLongwindedDescription:(SecCertificateRef) certificateRef {
if (certificateRef == NULL)
return #"";
CFStringRef commonNameRef;
OSStatus status;
if ((status=SecCertificateCopyCommonName(certificateRef, &commonNameRef)) != errSecSuccess) {
NSLog(#"Could not extract name from cert: %#",
SecCopyErrorMessageString(status, NULL));
return #"Unreadable cert";
};
CFStringRef summaryRef = SecCertificateCopySubjectSummary(certificateRef);
if (summaryRef == NULL)
summaryRef = CFRetain(commonNameRef);
CFErrorRef error;
const void *keys[] = { kSecOIDX509V1SubjectName, kSecOIDX509V1IssuerName };
const void *labels[] = { "Subject", "Issuer" };
CFArrayRef keySelection = CFArrayCreate(NULL, keys , sizeof(keys)/sizeof(keys[0]), &kCFTypeArrayCallBacks);
CFDictionaryRef vals = SecCertificateCopyValues(certificateRef, keySelection,&error);
NSMutableString *longDesc = [[NSMutableString alloc] init];
for(int i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) {
CFDictionaryRef dict = CFDictionaryGetValue(vals, keys[i]);
CFArrayRef values = CFDictionaryGetValue(dict, kSecPropertyKeyValue);
if (values == NULL)
continue;
[longDesc appendFormat:#"%s:%#\n\n", labels[i], [NSString stringFromDNwithSubjectName:values]];
}
CFRelease(vals);
CFRelease(summaryRef);
CFRelease(commonNameRef);
return longDesc;
}
The second function is an over the top try to extract anything you can get your mittens on:
+(NSString *)stringFromDNwithSubjectName:(CFArrayRef)array {
NSMutableString * out = [[NSMutableString alloc] init];
const void *keys[] = { kSecOIDCommonName, kSecOIDEmailAddress, kSecOIDOrganizationalUnitName, kSecOIDOrganizationName, kSecOIDLocalityName, kSecOIDStateProvinceName, kSecOIDCountryName };
const void *labels[] = { "CN", "E", "OU", "O", "L", "S", "C", "E" };
for(int i = 0; i < NVOID(keys); i++) {
for (CFIndex n = 0 ; n < CFArrayGetCount(array); n++) {
CFDictionaryRef dict = CFArrayGetValueAtIndex(array, n);
if (CFGetTypeID(dict) != CFDictionaryGetTypeID())
continue;
CFTypeRef dictkey = CFDictionaryGetValue(dict, kSecPropertyKeyLabel);
if (!CFEqual(dictkey, keys[i]))
continue;
CFStringRef str = (CFStringRef) CFDictionaryGetValue(dict, kSecPropertyKeyValue);
[out appendFormat:#"%s=%# ", labels[i], (__bridge NSString*)str];
}
}
return [NSString stringWithString:out];
}
I don't believe there is a public API to do this on iOS. On OSX there are a number of SecCertificate APIs to pick apart the X.509 information.
FYI, assuming you're using HTTPS, checking the CN yourself is mostly useless, because the OS already checks to make sure the name is present in the cert. You're more likely to want to check the public key (for key pinning), which you can get from the trust object without touching the certificate directly.
If the public key matches the previous key, then either the site is legit or somebody has thoroughly compromised the site.
I am writing an application that is communicating with a server which requires the client to authenticate itself using a client certificate. I need to extract the certificate from a .p12 file in the application bundle and add it to the application keychain.
I've been trying to figure out how to get it working from Apple's "Certificate, Key, and Trust Services Tasks for iOS", but to me it seems incomplete and does not specify how I add anything to the keychain(?).
I am quite lost and any help is appriciated, thanks in advance!
"Certificate, Key, and Trust Services Tasks for iOS" does contain sufficient information to extract certificate from a .p12 file.
from listing 2-1 demonstrate how you can extract SecIdentityRef
from listing 2-2 second line (// 1) shows how you can copy
SecCertificateRef out of SecIdentityRef.
example loading p12 file, extract certificate, install to keychain.
(error handling and memory management was not included)
NSString * password = #"Your-P12-File-Password";
NSString * path = [[NSBundle mainBundle]
pathForResource:#"Your-P12-File" ofType:#"p12"];
// prepare password
CFStringRef cfPassword = CFStringCreateWithCString(NULL,
password.UTF8String,
kCFStringEncodingUTF8);
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { cfPassword };
CFDictionaryRef optionsDictionary
= CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1,
NULL, NULL);
// prepare p12 file content
NSData * fileContent = [[NSData alloc] initWithContentsOfFile:path];
CFDataRef cfDataOfFileContent = (__bridge CFDataRef)fileContent;
// extract p12 file content into items (array)
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
OSStatus status = errSecSuccess;
status = SecPKCS12Import(cfDataOfFileContent,
optionsDictionary,
&items);
// TODO: error handling on status
// extract identity
CFDictionaryRef yourIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
const void *tempIdentity = NULL;
tempIdentity = CFDictionaryGetValue(yourIdentityAndTrust,
kSecImportItemIdentity);
SecIdentityRef yourIdentity = (SecIdentityRef)tempIdentity;
// get certificate from identity
SecCertificateRef yourCertificate = NULL;
status = SecIdentityCopyCertificate(yourIdentity, &yourCertificate);
// at last, install certificate into keychain
const void *keys2[] = { kSecValueRef, kSecClass };
const void *values2[] = { yourCertificate, kSecClassCertificate };
CFDictionaryRef dict
= CFDictionaryCreate(kCFAllocatorDefault, keys2, values2,
2, NULL, NULL);
status = SecItemAdd(dict, NULL);
// TODO: error handling on status
I have found an example about OPENSSL DES, when I applied this example into Objective-C program, the decrypted text was not equal to what I have input.
textField.text is the input textbox
Can anyone help me? Many thanks!!!
for e.g,
when I input "test", the decrypted text ="test&\264"
when I input "Enter an Text here", the decrypted text ="Ente"
when I input "1234567890", the decrypted text ="1234h&\311"
//ENCRYPTION
char* desen(char *clear, int size)
{
printf("Encrypted text\t %s \n",clear);
char *encrypted;
char key[]="password";
encrypted=(char*)malloc(sizeof(clear));
static char* Res;
int n=0;
DES_cblock Key2;
DES_key_schedule schedule;
Res = ( char * ) malloc( sizeof(clear) );
// Prepare the key for use with DES_cfb64_encrypt /
memcpy( Key2, key,8);
DES_set_odd_parity( &Key2 );
DES_set_key_checked( &Key2, &schedule );
// Encryption occurs here /
DES_cfb64_encrypt( ( unsigned char * ) clear, ( unsigned char * ) Res,
sizeof(clear), &schedule, &Key2, &n, DES_ENCRYPT );
memcpy(encrypted,Res, sizeof(clear));
printf("Key:%s\n",encrypted);
return encrypted;
}
//------------------------------------------------
//DECRYPTION-------------------------------
char* desde(char *clear, int size)
{
char *decrypted;
char key[]="password";
decrypted=(char*)malloc(sizeof(clear));
static char* Res;
int n=0;
DES_cblock Key2;
DES_key_schedule schedule;
Res = ( char * ) malloc( sizeof(clear) );
// Prepare the key for use with DES_cfb64_encrypt /
memcpy( Key2, key,8);
DES_set_odd_parity( &Key2 );
DES_set_key_checked( &Key2, &schedule );
// Encryption occurs here /
DES_cfb64_encrypt( ( unsigned char * ) clear, ( unsigned char * ) Res,
sizeof(clear), &schedule, &Key2, &n, DES_DECRYPT );
memcpy(decrypted,Res, sizeof(clear));
printf("Key:%s\n",decrypted);
return decrypted;
}
//------------------------------------------------
//----------Button------------------------------
- (IBAction)calculateDES_ENCRYPT:(id)sender
{
char key[]="password";
char *en;
char *de;
NSString *string = textField.text;
const char *temp=[string fileSystemRepresentation];
int len=strlen(temp);
char clear[len+1];
//char clear[50];
strcpy(clear,temp);
en=desen( clear,len+1);
de= desde(en, len+1);
}
------------------------------------------------
This line
encrypted=(char*)malloc(sizeof(clear));
doesn't do what you think. On a 32 bit system, sizeof(clear) will be 4 because it is the size of the pointer, not the length of the data pointed to. So you are probably only encrypting/decrypting 4 bytes and you are printing out those 4 bytes plus some garbage.