how hexadecimal string to Bytes and Bytes to hexadecimal string?
I have oc code but I can not to write in swift
can u help me ?
thanks so much
+ (NSData *)convertHexToDataBytes:(NSString *)hexStr {
NSMutableData *dataBytes = [NSMutableData data];
int idx;
for (idx = 0; idx + 2 <= hexStr.length; idx += 2) {
NSRange range = NSMakeRange(idx, 2);
NSString *singleHexStr = [hexStr substringWithRange:range];
NSScanner *scanner = [NSScanner scannerWithString:singleHexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[dataBytes appendBytes:&intValue length:1];
}
return dataBytes;
}
+ (NSString *)convertDataBytesToHex:(NSData *)dataBytes {
if (!dataBytes || [dataBytes length] == 0) {
return #"";
}
NSMutableString *hexStr = [[NSMutableString alloc] initWithCapacity:[dataBytes length]];
[dataBytes enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
unsigned char *dataBytes = (unsigned char *)bytes;
for (NSInteger i = 0; i < byteRange.length; i ++) {
NSString *singleHexStr = [NSString stringWithFormat:#"%x", (dataBytes[i]) & 0xff];
if ([singleHexStr length] == 2) {
[hexStr appendString:singleHexStr];
} else {
[hexStr appendFormat:#"0%#", singleHexStr];
}
}
}];
return hexStr;
}
I write in swift like this
class func convertHex(toDataBytes hexStr: String?) -> Data? {
var dataBytes = Data()
var idx: Int
idx = 0
while idx + 2 <= (hexStr?.count ?? 0) {
let range = NSRange(location: idx, length: 2)
let singleHexStr = (hexStr as NSString?)?.substring(with: range)
let scanner = Scanner(string: singleHexStr ?? "")
var intValue: UInt
scanner.scanHexInt32(&UInt32(intValue))
dataBytes.append(&intValue, count: 1)
idx += 2
}
return dataBytes
}
its error says:Cannot pass immutable value as inout argument: function call returns immutable value how to fix it?
To answer your immediate question: UInt32(intValue) creates a new (constant) value whose address cannot be taken with &. So
var intValue: UInt
scanner.scanHexInt32(&UInt32(intValue))
should be
var intValue: UInt32 = 0
scanner.scanHexInt32(&intValue)
And
dataBytes.append(&intValue, count: 1)
does not compile because &intValue is a pointer to an integer, not to an UInt8. Here you can do
dataBytes.append(UInt8(intValue))
because the value is known to fit in a single byte.
Having said that, all the conversions from String to NSString are not needed. A more “Swifty” translation of that Objective-C code to Swift would be
func convertHex(toDataBytes hexStr: String) -> Data {
var dataBytes = Data()
var startPos = hexStr.startIndex
while let endPos = hexStr.index(startPos, offsetBy: 2, limitedBy: hexStr.endIndex) {
let singleHexStr = hexStr[startPos..<endPos]
let scanner = Scanner(string: String(singleHexStr))
var intValue: UInt32 = 0
scanner.scanHexInt32(&intValue)
dataBytes.append(UInt8(intValue))
startPos = endPos
}
return dataBytes
}
For an alternative approach (which includes error checking) see for example
hex/binary string conversion in Swift
My server devs ask me to send them some data encoded with base64 with this rules:
big-endian byte order
no extra zero bytes
base64 string
for example:
10005000 → «mKol»
1234567890 → «SZYC0g»
I did some spaghetti code, and it's work. But maybe somebody have more elegant solution?
+ (NSString*)encodeBigEndianBase64:(uint32_t)value {
char *bytes = (char*) &value;
int len = sizeof(uint32_t);
char *reverseBytes = malloc(sizeof(char) * len);
unsigned long index = len - 1;
for (int i = 0; i < len; i++)
reverseBytes[index--] = bytes[i];
int offset = 0;
while (reverseBytes[offset] == 0) {
offset++;
}
NSData *resultData;
if (offset > 0) {
int truncatedLen = (len - offset);
char *truncateBytes = malloc(sizeof(char) * truncatedLen);
for (int i = 0; i < truncatedLen ; i++)
truncateBytes[i] = reverseBytes[i + offset];
resultData = [NSData dataWithBytes:truncateBytes length:truncatedLen];
free(truncateBytes);
} else {
resultData = [NSData dataWithBytes:reverseBytes length:len];
}
free(reverseBytes);
return [[resultData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength] stringByReplacingOccurrencesOfString:#"=" withString:#""];
}
Little bit improved solution (thanks to zaph):
+ (NSString*)encodeBigEndianBase64:(uint32_t)value {
uint32_t swappedValue = CFSwapInt32HostToBig(value);
char *swappedBytes = (char*) &swappedValue;
int len = sizeof(uint32_t);
int offset = 0;
while (swappedBytes[offset] == 0) {
offset++;
}
NSData *resultData;
if (offset > 0) {
int truncatedLen = (len - offset);
char *truncateBytes = malloc(sizeof(char) * truncatedLen);
for (int i = 0; i < truncatedLen ; i++)
truncateBytes[i] = swappedBytes[i + offset];
resultData = [NSData dataWithBytes:truncateBytes length:truncatedLen];
free(truncateBytes);
} else {
resultData = [NSData dataWithBytes:swappedBytes length:len];
}
return [[resultData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength] stringByReplacingOccurrencesOfString:#"=" withString:#""];
}
For endian conversions use htons(), htonl(), ntohs(), ntohl()
network byte order is bigendian
`htons()` // host to network short
`htonl()` // host to network ling
`ntohs()` // network to host long
`ntohl()` // network to host long
These are defined in endan.h
Also see Byte-Order Utilities Reference
I'm working with a partner and we're not able to get C# and Objective-C to produce the same hashes using what we think are the same tools in the respective languages. In C#, I'm doing this:
byte[] noncebytes=new byte[32];
//We seed the hash generator with a new 32 position array. Each position is 0.
//In prod code this would be random, but for now it's all 0s.
HMACSHA256 hmac256 = new HMACSHA256(noncebytes);
string plaintext = "hello";
string UTFString = Convert.ToBase64String(
System.Text.Encoding.UTF8.GetBytes(plaintext));
string HashString = Convert.ToBase64String(
hmac256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(plaintext))); //Convert that hash to a string.
This produces the following base64string hash:
Q1KybjP+DXaaiSKmuikAQQnwFojiasyebLNH5aWvxNo=
What is the equivalent Objective-C code to do this? We need the client and the server to be able to generate matching hashes for matching data.
Here is the Objective-C code we are currently using:
...
NSData *zeroNumber = [self zeroDataWithBytes:32]; //empty byte array
NSString *nonceTest = [zeroNumber base64String]; // using MF_Base64Additions.h here
NSData *hashTest = [self hmacForKeyAndData:nonceTest withData:#"hello"]; //creating hash
NSString *hashTestText = [hashTest base64String];
NSLog(#"hello hash is %#", hashTestText);
...
//functions for zeroing out the byte. I'm sure there's a better way
- (NSData *)zeroDataWithBytes: (NSUInteger)length {
NSMutableData *mutableData = [NSMutableData dataWithCapacity: length];
for (unsigned int i = 0; i < length; i++) {
NSInteger bits = 0;
[mutableData appendBytes: (void *) &bits length: 1];
} return mutableData;
}
//hash function
-(NSData *) hmacForKeyAndData:(NSString *)key withData:(NSString *) data {
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
}
UPDATE:
There is a pretty good project on GitHub that seems to accomplish everything you want, plus a lot more encryption related options; includes unit tests.
NSData *hmacForKeyAndData(NSString *key, NSString *data)
{
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
}
(Source)
With the above, I think you will have import <CommonCrypto/CommonHMAC.h>. The next step for encoding to Base64:
+ (NSString *)Base64Encode:(NSData *)data
{
//Point to start of the data and set buffer sizes
int inLength = [data length];
int outLength = ((((inLength * 4)/3)/4)*4) + (((inLength * 4)/3)%4 ? 4 : 0);
const char *inputBuffer = [data bytes];
char *outputBuffer = malloc(outLength);
outputBuffer[outLength] = 0;
//64 digit code
static char Encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//start the count
int cycle = 0;
int inpos = 0;
int outpos = 0;
char temp;
//Pad the last to bytes, the outbuffer must always be a multiple of 4
outputBuffer[outLength-1] = '=';
outputBuffer[outLength-2] = '=';
/* http://en.wikipedia.org/wiki/Base64
Text content M a n
ASCII 77 97 110
8 Bit pattern 01001101 01100001 01101110
6 Bit pattern 010011 010110 000101 101110
Index 19 22 5 46
Base64-encoded T W F u
*/
while (inpos < inLength){
switch (cycle) {
case 0:
outputBuffer[outpos++] = Encode[(inputBuffer[inpos]&0xFC)>>2];
cycle = 1;
break;
case 1:
temp = (inputBuffer[inpos++]&0x03)<<4;
outputBuffer[outpos] = Encode[temp];
cycle = 2;
break;
case 2:
outputBuffer[outpos++] = Encode[temp|(inputBuffer[inpos]&0xF0)>> 4];
temp = (inputBuffer[inpos++]&0x0F)<<2;
outputBuffer[outpos] = Encode[temp];
cycle = 3;
break;
case 3:
outputBuffer[outpos++] = Encode[temp|(inputBuffer[inpos]&0xC0)>>6];
cycle = 4;
break;
case 4:
outputBuffer[outpos++] = Encode[inputBuffer[inpos++]&0x3f];
cycle = 0;
break;
default:
cycle = 0;
break;
}
}
NSString *pictemp = [NSString stringWithUTF8String:outputBuffer];
free(outputBuffer);
return pictemp;
}
Note the second line of code in the objective-c portion of the question.
NSString *nonceTest = [zeroNumber base64String];
but it should be this:
NSString *nonceTest = [[NSString alloc] initWithData:zeroNumber encoding:NSASCIIStringEncoding];
It was a case of converting the string to base64 when we didn't need to for the hmac seeeding.
We now get: Q1KybjP+DXaaiSKmuikAQQnwFojiasyebLNH5aWvxNo= as the hash on both platforms.
I want to call a method, pass it the length and have it generate a random alphanumeric string.
Are there any utility libraries out there that may have a bunch of these types of functions?
Here's a quick and dirty implementation. Hasn't been tested.
NSString *letters = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-(NSString *) randomStringWithLength: (int) len {
NSMutableString *randomString = [NSMutableString stringWithCapacity: len];
for (int i=0; i<len; i++) {
[randomString appendFormat: #"%C", [letters characterAtIndex: arc4random_uniform([letters length])]];
}
return randomString;
}
Not exactly what you ask, but still useful:
[[NSProcessInfo processInfo] globallyUniqueString]
Sample output:
450FEA63-2286-4B49-8ACC-9822C7D4356B-1376-00000239A4AC4FD5
NSString *alphabet = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789";
NSMutableString *s = [NSMutableString stringWithCapacity:20];
for (NSUInteger i = 0U; i < 20; i++) {
u_int32_t r = arc4random() % [alphabet length];
unichar c = [alphabet characterAtIndex:r];
[s appendFormat:#"%C", c];
}
Surely you can make this shorter:
+(NSString*)generateRandomString:(int)num {
NSMutableString* string = [NSMutableString stringWithCapacity:num];
for (int i = 0; i < num; i++) {
[string appendFormat:#"%C", (unichar)('a' + arc4random_uniform(26))];
}
return string;
}
If you're willing to limit yourself to hex characters only, then the simplest option is to generate a UUID:
NSString *uuid = [NSUUID UUID].UUIDString;
Example output: 16E3DF0B-87B3-4162-A1A1-E03DB2F59654.
If you want a smaller random string then you can grab just the first 8 characters.
It's a version 4 UUID which means the first character in the 3rd and 4th group is not random (they will always be 4 and one of 8, 9, A or B).
Every other character in the string is fully random and you can generate millions of UUIDs every second for hundreds of years without much risk of the same UUID being generated twice.
A category version of Jeff B's answer.
NSString+Random.h
#import <Foundation/Foundation.h>
#interface NSString (Random)
+ (NSString *)randomAlphanumericStringWithLength:(NSInteger)length;
#end
NSString+Random.m
#import "NSString+Random.h"
#implementation NSString (Random)
+ (NSString *)randomAlphanumericStringWithLength:(NSInteger)length
{
NSString *letters = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
NSMutableString *randomString = [NSMutableString stringWithCapacity:length];
for (int i = 0; i < length; i++) {
[randomString appendFormat:#"%C", [letters characterAtIndex:arc4random() % [letters length]]];
}
return randomString;
}
#end
You could also just generate a UUID. While not truly random, they are complex and unique which makes them appear random for most uses. Generate one as a string and then take a range of characters equal to the passed length.
Swift
func randomStringWithLength(length: Int) -> String {
let alphabet = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
let upperBound = UInt32(count(alphabet))
return String((0..<length).map { _ -> Character in
return alphabet[advance(alphabet.startIndex, Int(arc4random_uniform(upperBound)))]
})
}
Here's a different way to tackle it. Instead of using a prepared string of characters, you can cast between integers and characters, and generate a dynamic list of characters to select. It's pretty lean and fast, but has a bit more code.
int charNumStart = (int) '0';
int charNumEnd = (int) '9';
int charCapitalStart = (int) 'A';
int charCapitalEnd = (int) 'Z';
int charLowerStart = (int) 'a';
int charLowerEnd = (int) 'z';
int amountOfChars = (charNumEnd - charNumStart) + (charCapitalEnd - charCapitalStart) + (charLowerEnd - charLowerStart); // amount of the characters we want.
int firstGap = charCapitalStart - charNumEnd; // there are gaps of random characters between numbers and uppercase letters, so this allows us to skip those.
int secondGap = charLowerStart - charCapitalEnd; // similar to above, but between uppercase and lowercase letters.
// START generates a log to show us which characters we are considering for our UID.
NSMutableString *chars = [NSMutableString stringWithCapacity:amountOfChars];
for (int i = charNumStart; i <= charLowerEnd; i++) {
if ((i >= charNumStart && i <= charNumEnd) || (i >= charCapitalStart && i <= charCapitalEnd) || (i >= charLowerStart && i <= charLowerEnd)) {
[chars appendFormat:#"\n%c", (char) i];
}
}
NSLog(#"chars: %#", chars);
// END log
// Generate a uid of 20 characters that chooses from our desired range.
int uidLength = 20;
NSMutableString *uid = [NSMutableString stringWithCapacity:uidLength];
for (int i = 0; i < uidLength; i++) {
// Generate a random number within our character range.
int randomNum = arc4random() % amountOfChars;
// Add the lowest value number to line this up with a desirable character.
randomNum += charNumStart;
// if the number is in the letter range, skip over the characters between the numbers and letters.
if (randomNum > charNumEnd) {
randomNum += firstGap;
}
// if the number is in the lowercase letter range, skip over the characters between the uppercase and lowercase letters.
if (randomNum > charCapitalEnd) {
randomNum += secondGap;
}
// append the chosen character.
[uid appendFormat:#"%c", (char) randomNum];
}
NSLog(#"uid: %#", uid);
// Generate a UID that selects any kind of character, including a lot of punctuation. It's a bit easier to do it this way.
int amountOfAnyCharacters = charLowerEnd - charNumStart; // A new range of characters.
NSMutableString *multiCharUid = [NSMutableString stringWithCapacity:uidLength];
for (int i = 0; i < uidLength; i++) {
// Generate a random number within our new character range.
int randomNum = arc4random() % amountOfAnyCharacters;
// Add the lowest value number to line this up with our range of characters.
randomNum += charNumStart;
// append the chosen character.
[multiCharUid appendFormat:#"%c", (char) randomNum];
}
NSLog(#"multiCharUid: %#", multiCharUid);
When I'm doing random character generation, I prefer to work directly with integers and cast them over, instead of writing out the list of chars that I want to draw from. Declaring the variables at the top makes it more system independent, but this code assumes that numbers will have a lower value than letters, and that uppercase letters will have a lower value than lowercase letters.
Alternative solution in Swift
func generateString(len: Int) -> String {
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let lettersLength = UInt32(countElements(letters))
let result = (0..<len).map { _ -> String in
let idx = Int(arc4random_uniform(lettersLength))
return String(letters[advance(letters.startIndex, idx)])
}
return "".join(result)
}
Modification of a few ideas here, and in done Swift 4.0
extension String
{
subscript (i: Int) -> Character
{
return self[index(startIndex, offsetBy:i)]
}
static func Random(length:Int=32, alphabet:String="ABCDEF0123456789") -> String
{
let upperBound = UInt32(alphabet.count)
return String((0..<length).map { _ -> Character in
return alphabet[Int(arc4random_uniform(upperBound))]
})
}
}
Usage:
let myHexString = String.Random()
let myLongHexString = String.Random(length:64)
let myLettersString = String.Random(length:32, alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZ")
If you want a random unicode string, you can create random bytes and then use the valid ones.
OSStatus sanityCheck = noErr;
uint8_t * randomBytes = NULL;
size_t length = 200; // can of course be variable
randomBytes = malloc( length * sizeof(uint8_t) );
memset((void *)randomBytes, 0x0, length);
sanityCheck = SecRandomCopyBytes(kSecRandomDefault, length, randomBytes);
if (sanityCheck != noErr) NSLog(#"Error generating random bytes, OSStatus == %ld.", sanityCheck);
NSData* randomData = [[NSData alloc] initWithBytes:(const void *)randomBytes length: length];
if (randomBytes) free(randomBytes);
NSString* dataString = [[NSString alloc] initWithCharacters:[randomData bytes] length:[randomData length]]; // create an NSString from the random bytes
NSData* tempData = [dataString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; // remove illegal characters from string
NSString* randomString = [[NSString alloc] initWithData:tempData encoding:NSUTF8StringEncoding];
The conversion from NSString to NSData and back is necessary to get a valid UTF-8 string.
Be aware that length will not necessarily be the length of the the NSString created in the end.
I did this using a simple char[] instead of an NSString * for the alphabet. I added this to a NSString category.
static const char __alphabet[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
+ (NSString *)randomString:(int)length
{
NSMutableString *randomString = [NSMutableString stringWithCapacity:length];
u_int32_t alphabetLength = (u_int32_t)strlen(__alphabet);
for (int i = 0; i < length; i++) {
[randomString appendFormat:#"%c", __alphabet[arc4random_uniform(alphabetLength)]];
}
return randomString;
}
Adding to good answer given by Melvin, here is a function I made (in SWIFT!) to get a random string:
func randomStringOfLength(length:Int)->String{
var wantedCharacters:NSString="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789"
var s=NSMutableString(capacity: length)
for (var i:Int = 0; i < length; i++) {
let r:UInt32 = arc4random() % UInt32( wantedCharacters.length)
let c:UniChar = wantedCharacters.characterAtIndex( Int(r) )
s.appendFormat("%C", c)
}
return s
}
Here is a test result from calling randomStringOfLength(10): uXa0igA8wm
static NSUInteger length = 32;
static NSString *letters = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
NSMutableString * randomString = [NSMutableString stringWithCapacity:length];
for (NSInteger i = 0; i < length; ++i) {
[randomString appendFormat: #"%C", [letters characterAtIndex:(NSUInteger)arc4random_uniform((u_int32_t)[letters length])]];
}
Generates lowercase alphanumeric random string with given length:
-(NSString*)randomStringWithLength:(NSUInteger)length
{
NSMutableString* random = [NSMutableString stringWithCapacity:length];
for (NSUInteger i=0; i<length; i++)
{
char c = '0' + (unichar)arc4random()%36;
if(c > '9') c += ('a'-'9'-1);
[random appendFormat:#"%c", c];
}
return random;
}
Method to call:
NSString *string = [self stringWithRandomSuffixForFile:#"file.pdf" withLength:4]
Method:
- (NSString *)stringWithRandomSuffixForFile:(NSString *)file withLength:(int)length
{
NSString *alphabet = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
NSString *fileExtension = [file pathExtension];
NSString *fileName = [file stringByDeletingPathExtension];
NSMutableString *randomString = [NSMutableString stringWithFormat:#"%#_", fileName];
for (int x = 0; x < length; x++) {
[randomString appendFormat:#"%C", [alphabet characterAtIndex: arc4random_uniform((int)[alphabet length]) % [alphabet length]]];
}
[randomString appendFormat:#".%#", fileExtension];
NSLog(#"## randomString: %# ##", randomString);
return randomString;
}
Results:
## randomString: file_Msci.pdf ##
## randomString: file_xshG.pdf ##
## randomString: file_abAD.pdf ##
## randomString: file_HVwV.pdf ##
for Swift 3.0
func randomString(_ length: Int) -> String {
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let len = UInt32(letters.length)
var randomString = ""
for _ in 0 ..< length {
let rand = arc4random_uniform(len)
var nextChar = letters.character(at: Int(rand))
randomString += NSString(characters: &nextChar, length: 1) as String
}
return randomString
}
#define ASCII_START_NUMERS 0x30
#define ASCII_END_NUMERS 0x39
#define ASCII_START_LETTERS_A 0x41
#define ASCII_END_LETTERS_Z 0x5A
#define ASCII_START_LETTERS_a 0x61
#define ASCII_END_LETTERS_z 0x5A
-(NSString *)getRandomString:(int)length {
NSMutableString *result = [[NSMutableString alloc]init];
while (result.length != length) {
NSMutableData* data = [NSMutableData dataWithLength:1];
SecRandomCopyBytes(kSecRandomDefault, 1, [data mutableBytes]);
Byte currentChar = 0;
[data getBytes:¤tChar length:1];
NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (currentChar > ASCII_START_NUMERS && currentChar < ASCII_END_NUMERS) { // 0 to 0
[result appendString:s];
continue;
}
if (currentChar > ASCII_START_LETTERS_A && currentChar < ASCII_END_LETTERS_Z) { // 0 to 0
[result appendString:s];
continue;
}
if (currentChar > ASCII_START_LETTERS_a && currentChar < ASCII_END_LETTERS_z) { // 0 to 0
[result appendString:s];
continue;
}
}
return result;
}
Modification for keithyip's answer:
+ (NSString *)randomAlphanumericStringWithLength:(NSInteger)length
{
static NSString * const letters = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
srand(time(NULL));
});
NSMutableString *randomString = [NSMutableString stringWithCapacity:length];
for (int i = 0; i < length; i++) {
[randomString appendFormat:#"%C", [letters characterAtIndex:arc4random() % [letters length]]];
}
return randomString;
}
How do I do Base64 encoding on the iPhone?
I have found a few examples that looked promising, but could never get any of them to work on the phone.
You can see an example here.
This is for iOS7+.
I copy the code here, just in case:
// Create NSData object
NSData *nsdata = [#"iOS Developer Tips encoded in Base64"
dataUsingEncoding:NSUTF8StringEncoding];
// Get NSString from NSData object in Base64
NSString *base64Encoded = [nsdata base64EncodedStringWithOptions:0];
// Print the Base64 encoded string
NSLog(#"Encoded: %#", base64Encoded);
// Let's go the other way...
// NSData from the Base64 encoded str
NSData *nsdataFromBase64String = [[NSData alloc]
initWithBase64EncodedString:base64Encoded options:0];
// Decoded NSString from the NSData
NSString *base64Decoded = [[NSString alloc]
initWithData:nsdataFromBase64String encoding:NSUTF8StringEncoding];
NSLog(#"Decoded: %#", base64Decoded);
Use this library to encode Base64.
It also supports ARC
I also had trouble finding working code for the iPhone that I could understand.
I finally wrote this.
-(NSString *)Base64Encode:(NSData *)data;
-(NSString *)Base64Encode:(NSData *)data{
//Point to start of the data and set buffer sizes
int inLength = [data length];
int outLength = ((((inLength * 4)/3)/4)*4) + (((inLength * 4)/3)%4 ? 4 : 0);
const char *inputBuffer = [data bytes];
char *outputBuffer = malloc(outLength+1);
outputBuffer[outLength] = 0;
//64 digit code
static char Encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//Start the count
int cycle = 0;
int inpos = 0;
int outpos = 0;
char temp;
//Pad the last to bytes, the outbuffer must always be a multiple of 4.
outputBuffer[outLength-1] = '=';
outputBuffer[outLength-2] = '=';
/* http://en.wikipedia.org/wiki/Base64
Text content M a n
ASCII 77 97 110
8 Bit pattern 01001101 01100001 01101110
6 Bit pattern 010011 010110 000101 101110
Index 19 22 5 46
Base64-encoded T W F u
*/
while (inpos < inLength){
switch (cycle) {
case 0:
outputBuffer[outpos++] = Encode[(inputBuffer[inpos] & 0xFC) >> 2];
cycle = 1;
break;
case 1:
temp = (inputBuffer[inpos++] & 0x03) << 4;
outputBuffer[outpos] = Encode[temp];
cycle = 2;
break;
case 2:
outputBuffer[outpos++] = Encode[temp|(inputBuffer[inpos]&0xF0) >> 4];
temp = (inputBuffer[inpos++] & 0x0F) << 2;
outputBuffer[outpos] = Encode[temp];
cycle = 3;
break;
case 3:
outputBuffer[outpos++] = Encode[temp|(inputBuffer[inpos]&0xC0) >> 6];
cycle = 4;
break;
case 4:
outputBuffer[outpos++] = Encode[inputBuffer[inpos++] & 0x3f];
cycle = 0;
break;
default:
cycle = 0;
break;
}
}
NSString *pictemp = [NSString stringWithUTF8String:outputBuffer];
free(outputBuffer);
return pictemp;
}
Download following two files from GitHub
Base64.h
Base64.m
Add these files to your project
Import header file in desired file
#import "Base64.h"
And use as to encode
NSString *plainText = #"Your String";
NSString *base64String = [plainText base64EncodedStringWithWrapWidth:0];
Also you can decode it as
NSString *plainText = [base64String base64DecodedString];
Try this out...this worked perfectly for me.create a category Base64.h and Base 64.m,Import to any class you want to use and call it using single line for base 64 encoding to happen.
//
// Base64.h
// CryptTest
// Created by SURAJ K THOMAS on 02/05/2013.
#import <Foundation/Foundation.h>
#interface Base64 : NSObject {
}
+ (void) initialize;
+ (NSString*) encode:(const uint8_t*) input length:(NSInteger) length;
+ (NSString*) encode:(NSData*) rawBytes;
+ (NSData*) decode:(const char*) string length:(NSInteger) inputLength;
+ (NSData*) decode:(NSString*) string;
#end
#import "Base64.h"
#implementation Base64
#define ArrayLength(x) (sizeof(x)/sizeof(*(x)))
static char encodingTable[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static char decodingTable[128];
+ (void) initialize {
if (self == [Base64 class]) {
memset(decodingTable, 0, ArrayLength(decodingTable));
for (NSInteger i = 0; i < ArrayLength(encodingTable); i++) {
decodingTable[encodingTable[i]] = i;
}
}
}
+ (NSString*) encode:(const uint8_t*) input length:(NSInteger) length {
NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t* output = (uint8_t*)data.mutableBytes;
for (NSInteger i = 0; i < length; i += 3) {
NSInteger value = 0;
for (NSInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger index = (i / 3) * 4;
output[index + 0] = encodingTable[(value >> 18) & 0x3F];
output[index + 1] = encodingTable[(value >> 12) & 0x3F];
output[index + 2] = (i + 1) < length ? encodingTable[(value >> 6) & 0x3F] : '=';
output[index + 3] = (i + 2) < length ? encodingTable[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:data
encoding:NSASCIIStringEncoding];
}
+ (NSString*) encode:(NSData*) rawBytes {
return [self encode:(const uint8_t*) rawBytes.bytes length:rawBytes.length];
}
+ (NSData*) decode:(const char*) string length:(NSInteger) inputLength {
if ((string == NULL) || (inputLength % 4 != 0)) {
return nil;
}
while (inputLength > 0 && string[inputLength - 1] == '=') {
inputLength--;
}
NSInteger outputLength = inputLength * 3 / 4;
NSMutableData* data = [NSMutableData dataWithLength:outputLength];
uint8_t* output = data.mutableBytes;
NSInteger inputPoint = 0;
NSInteger outputPoint = 0;
while (inputPoint < inputLength) {
char i0 = string[inputPoint++];
char i1 = string[inputPoint++];
char i2 = inputPoint < inputLength ? string[inputPoint++] : 'A'; /* 'A' will
decode to \0 */
char i3 = inputPoint < inputLength ? string[inputPoint++] : 'A';
output[outputPoint++] = (decodingTable[i0] << 2) | (decodingTable[i1] >> 4);
if (outputPoint < outputLength) {
output[outputPoint++] = ((decodingTable[i1] & 0xf) << 4) |
(decodingTable[i2] >> 2);
}
if (outputPoint < outputLength) {
output[outputPoint++] = ((decodingTable[i2] & 0x3) << 6) |
decodingTable[i3];
}
}
return data;
}
+ (NSData*) decode:(NSString*) string {
return [self decode:[string cStringUsingEncoding:NSASCIIStringEncoding]
length:string.length];
}
#end
now import the above category to any class and convert the string like below
NSString *authString = [[NSString stringWithFormat:#"OD0EK819OJFIFT6OJZZXT09Y1YUT1EJ2"]
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *inputData = [authString dataUsingEncoding:NSUTF8StringEncoding];
NSString *finalAuth =[Base64 encode:inputData];
NSLog(#"Encoded string =%#", finalAuth);
reference
NSString *plainString = #"foo";
Encoding
NSData *plainData = [plainString dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64String = [plainData base64EncodedStringWithOptions:0];
NSLog(#"%#", base64String); // Zm9v
Decoding
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
NSString *decodedString = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
NSLog(#"%#", decodedString); // foo
Seems as of iOS 7 you no longer need any libraries to encode in Base64. Following methods on NSData can be used to Base64 encode:
base64EncodedDataWithOptions:
– base64EncodedStringWithOptions:
I did my own implementation, where has been removed all checks inside the loop. So on big amount of data, it works faster. You can take it as a basis for own solution.
static char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ (NSString *)encodeString:(NSString *)data
{
const char *input = [data cStringUsingEncoding:NSUTF8StringEncoding];
unsigned long inputLength = [data length];
unsigned long modulo = inputLength % 3;
unsigned long outputLength = (inputLength / 3) * 4 + (modulo ? 4 : 0);
unsigned long j = 0;
// Do not forget about trailing zero
unsigned char *output = malloc(outputLength + 1);
output[outputLength] = 0;
// Here are no checks inside the loop, so it works much faster than other implementations
for (unsigned long i = 0; i < inputLength; i += 3) {
output[j++] = alphabet[ (input[i] & 0xFC) >> 2 ];
output[j++] = alphabet[ ((input[i] & 0x03) << 4) | ((input[i + 1] & 0xF0) >> 4) ];
output[j++] = alphabet[ ((input[i + 1] & 0x0F)) << 2 | ((input[i + 2] & 0xC0) >> 6) ];
output[j++] = alphabet[ (input[i + 2] & 0x3F) ];
}
// Padding in the end of encoded string directly depends of modulo
if (modulo > 0) {
output[outputLength - 1] = '=';
if (modulo == 1)
output[outputLength - 2] = '=';
}
NSString *s = [NSString stringWithUTF8String:(const char *)output];
free(output);
return s;
}
This answer is outdated, use https://stackoverflow.com/a/24468530/669586 since iOS 7.
A method in a NSData category
- (NSString*)encodeBase64 {
static char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
unsigned int length = self.length;
unsigned const char* rawData = self.bytes;
//empty data = empty output
if (length == 0) {
return #"";
}
unsigned int outputLength = (((length + 2) / 3) * 4);
//let's allocate buffer for the output
char* rawOutput = malloc(outputLength + 1);
//with each step we get 3 bytes from the input and write 4 bytes to the output
for (unsigned int i = 0, outputIndex = 0; i < length; i += 3, outputIndex += 4) {
BOOL triple = NO;
BOOL quad = NO;
//get 3 bytes (or only 1 or 2 when we have reached the end of input)
unsigned int value = rawData[i];
value <<= 8;
if (i + 1 < length) {
value |= rawData[i + 1];
triple = YES;
}
value <<= 8;
if (i + 2 < length) {
value |= rawData[i + 2];
quad = YES;
}
//3 * 8 bits written as 4 * 6 bits (indexing the 64 chars of the alphabet)
//write = if end of input reached
rawOutput[outputIndex + 3] = (quad) ? alphabet[value & 0x3F] : '=';
value >>= 6;
rawOutput[outputIndex + 2] = (triple) ? alphabet[value & 0x3F] : '=';
value >>= 6;
rawOutput[outputIndex + 1] = alphabet[value & 0x3F];
value >>= 6;
rawOutput[outputIndex] = alphabet[value & 0x3F];
}
rawOutput[outputLength] = 0;
NSString* output = [NSString stringWithCString:rawOutput encoding:NSASCIIStringEncoding];
free(rawOutput);
return output;
}