127

I am storing a openssl private Key EVP_PKEY as nsdata. For this I am serializing into a byte stream using the code below

unsigned char *buf, *p;
int len;
len = i2d_PrivateKey(pkey, NULL);
buf = OPENSSL_malloc(len); 
p = buf;
i2d_PrivateKey(pkey, &p);

where pkey is of type EVP_PKEY. Then I am storing the bytes from buffer 'p' as an NSData using the line given below

NSData *keydata = [NSData dataWithBytes:P length:len];

Now I am converting it to a NSString using the code given below but when i print it into console its giving some other characters.

NSString *content =[ NSString stringWithCString:[keydata bytes] encoding:NSUTF8StringEncoding];

Could someone help?

Basically I want to store the EVP_PKEY into a sqlite database

am I on the right track? Thanks.

Zach
  • 9,989
  • 19
  • 70
  • 107
  • What do you mean, "some other characters"? Is it printing extra characters at the end that shouldn't be there, or is it just printing completely different characters than you expect? – Tom Harrington Jun 21 '11 at 17:33
  • Its completely different from what it is to be – Zach Jun 21 '11 at 21:44
  • Are you sure that the data is actually UTF-8 encoded? I'm not familiar with i2d_PrivateKey but your results suggest you're not using the right string encoding. – Tom Harrington Jun 22 '11 at 16:15
  • @TOm: Thanks. it was ASCIIEncoding. Now its working fine – Zach Jun 24 '11 at 14:07
  • No, you are not on the right track here, and all the answers seem incorrect. You should use base64 encoding if you want to convert the data in `NSData` to `NSString`. – Maarten Bodewes Aug 06 '13 at 16:19

6 Answers6

269

Objective-C

You can use (see NSString Class Reference)

- (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding

Example:

NSString *myString = [[NSString alloc] initWithData:myData encoding:NSUTF8StringEncoding];

Remark: Please notice the NSData value must be valid for the encoding specified (UTF-8 in the example above), otherwise nil will be returned:

Returns nil if the initialization fails for some reason (for example if data does not represent valid data for encoding).

Prior Swift 3.0

String(data: yourData, encoding: NSUTF8StringEncoding)

Swift 3.0 Onwards

String(data: yourData, encoding: .utf8)

See String#init(data:encoding:) Reference

Max MacLeod
  • 26,115
  • 13
  • 104
  • 132
louiscoquio
  • 10,638
  • 3
  • 33
  • 51
  • Thanks for your reply.I have already tried that with no success. – Zach Jun 21 '11 at 16:20
  • @bshirley:Yes we tried that ..still not working ..can you please suggest me a way to store my evp_key in my sqlite database – Zach Jun 21 '11 at 16:32
  • 26
    On the debugger: `po [[NSString alloc] initWithData:myData encoding:4]` – Berik Nov 01 '12 at 16:04
  • 8
    How can this answer have numerous upvotes, even though the `NSData` may contain any byte value, including those outside the UTF-8 range? – Maarten Bodewes Aug 06 '13 at 16:20
  • 2
    Because the people that are here are converting a data response from a server to a string. – Necro Nov 21 '13 at 04:58
  • @owlstead I've updated my answer. The readers are now aware that the NSData value must be valid for the specified encoding. Thanks! – louiscoquio Nov 21 '13 at 08:46
  • 1
    what if NSData indeed contain values outside of UTF-8 range? – Zennichimaro Feb 06 '15 at 08:55
  • According to the documentation, `nil` will be returned. I've updated my answer accordingly – louiscoquio Feb 06 '15 at 09:13
  • Is there a handy way to deal with NSData that's mostly string data, but not entirely? I'm trying to develop methods to "see" what's being sent to the server when debugging. I have multipart data including an image; I'm not surprised that it isn't all valid UTF8, but I'd love to see it with some sort of indicator character like ∅ over those bytes, so that I can see the vast majority of the data which makes valid characters... all the multipart headers, for one thing. – Apollo Grace Sep 24 '16 at 20:13
24

Prior Swift 3.0 :

String(data: yourData, encoding: NSUTF8StringEncoding)

For Swift 4.0:

String(data: yourData, encoding: .utf8)
PinkeshGjr
  • 8,460
  • 5
  • 41
  • 56
pierre23
  • 3,846
  • 1
  • 28
  • 28
4

Swift 5:

String(data: data!, encoding: String.Encoding.utf8)
Alexander Volkov
  • 7,904
  • 1
  • 47
  • 44
  • This just a modified copy of pierre23 answer that is better for me - I usually used this page to copy the code and had to modify yourData to data! that takes time. Now I and you copy and paste without a modification. – Alexander Volkov Aug 18 '16 at 08:49
  • This is not a Swift related question. More, the code sample in the question is Objective-C code. And not lastly the forced unwrap from your code can lead to unexpected crashes. – Cristik Aug 18 '16 at 10:10
  • @Cristik The question is not tagged as Obj-C. – Eiko Aug 20 '16 at 23:06
  • @AlexanderVolkov you can add an Xcode snippet for that, it would be even faster than this ;) – Cristik Aug 22 '16 at 18:02
3

I believe your "P" as the dataWithBytes param

NSData *keydata = [NSData dataWithBytes:P length:len];

should be "buf"

NSData *keydata = [NSData dataWithBytes:buf length:len];

since i2d_PrivateKey puts the pointer to the output buffer p at the end of the buffer and waiting for further input, and buf is still pointing to the beginning of your buffer.

The following code works for me where pkey is a pointer to an EVP_PKEY:

unsigned char *buf, *pp;
int len = i2d_PrivateKey(pkey, NULL);
buf = OPENSSL_malloc(len); 
pp = buf;
i2d_PrivateKey(pkey, &pp);

NSData* pkeyData = [NSData dataWithBytes:(const void *)buf length:len];
DLog(@"Private key in hex (%d): %@", len, pkeyData);

You can use an online converter to convert your binary data into base 64 (http://tomeko.net/online_tools/hex_to_base64.php?lang=en) and compare it to the private key in your cert file after using the following command and checking the output of mypkey.pem:

openssl pkcs12 -in myCert.p12 -nocerts -nodes -out mypkey.pem

I referenced your question and this EVP function site for my answer.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
aspergillusOryzae
  • 746
  • 2
  • 9
  • 25
2

Swift 3:

String(data: data, encoding: .utf8)
Travis M.
  • 10,930
  • 1
  • 56
  • 72
1

A simple way to convert arbitrary NSData to NSString is to base64 encode it.

NSString *base64EncodedKey = [keydata base64EncodedStringWithOptions: NSDataBase64Encoding64CharacterLineLength];

You can then store it into your database for reuse later. Just decode it back to NSData.

Billy
  • 437
  • 1
  • 6
  • 13