Last active
November 24, 2016 11:43
-
-
Save stevestreza/2557dc5ec9e7c694d7ea to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Base32.swift | |
// Created by Steve Streza on 26.9.14. | |
// | |
import Foundation | |
func Base32Encode(data: NSData) -> String { | |
let alphabet = [ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "2", "3", "4", "5", "6", "7"] | |
return Base32Encode(data, alphabet) | |
} | |
func Base32HexEncode(data: NSData) -> String { | |
let alphabet = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V"] | |
return Base32Encode(data, alphabet) | |
} | |
func Base32Decode(data: String) -> NSData? { | |
let characters = [ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "2", "3", "4", "5", "6", "7"] | |
let __ = 255 | |
let alphabet = [ | |
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x00 - 0x0F | |
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x10 - 0x1F | |
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x20 - 0x2F | |
__,__,26,27, 28,29,30,31, __,__,__,__, __, 0,__,__, // 0x30 - 0x3F | |
__, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, // 0x40 - 0x4F | |
15,16,17,18, 19,20,21,22, 23,24,25,__, __,__,__,__, // 0x50 - 0x5F | |
__, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, // 0x60 - 0x6F | |
15,16,17,18, 19,20,21,22, 23,24,25,__, __,__,__,__, // 0x70 - 0x7F | |
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x80 - 0x8F | |
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x90 - 0x9F | |
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xA0 - 0xAF | |
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xB0 - 0xBF | |
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xC0 - 0xCF | |
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xD0 - 0xDF | |
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xE0 - 0xEF | |
__,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xF0 - 0xFF | |
] | |
return Base32Decode(data, alphabet, characters) | |
} | |
//func Base32HexDecode(data: String) -> NSData? { | |
// let alphabet = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V"] | |
// return Base32Decode(data, alphabet) | |
//} | |
func Base32Encode(data: NSData, alphabet: Array<String>) -> String { | |
let numberOfBlocks = Int(ceil(Double(data.length) / Double(5))) | |
var result = String() | |
let bytes = UnsafePointer<UInt8>(data.bytes) | |
for byteIndex in stride(from: 0, to: data.length, by: 5) { | |
let maxOffset = (byteIndex + 5 >= data.length) ? data.length : byteIndex + 5 | |
let numberOfBytes = maxOffset - byteIndex | |
var byte0: UInt8 = 0 | |
var byte1: UInt8 = 0 | |
var byte2: UInt8 = 0 | |
var byte3: UInt8 = 0 | |
var byte4: UInt8 = 0 | |
switch numberOfBytes { | |
case 5: | |
byte4 = UInt8(bytes[byteIndex + 4]) | |
fallthrough | |
case 4: | |
byte3 = UInt8(bytes[byteIndex + 3]) | |
fallthrough | |
case 3: | |
byte2 = UInt8(bytes[byteIndex + 2]) | |
fallthrough | |
case 2: | |
byte1 = UInt8(bytes[byteIndex + 1]) | |
fallthrough | |
case 1: | |
byte0 = UInt8(bytes[byteIndex + 0]) | |
fallthrough | |
default: | |
break | |
} | |
var encodedByte0 = "=" | |
var encodedByte1 = "=" | |
var encodedByte2 = "=" | |
var encodedByte3 = "=" | |
var encodedByte4 = "=" | |
var encodedByte5 = "=" | |
var encodedByte6 = "=" | |
var encodedByte7 = "=" | |
switch numberOfBytes { | |
case 5: | |
encodedByte7 = alphabet[Int( byte4 & 0x1F )] | |
fallthrough; | |
case 4: | |
encodedByte6 = alphabet[Int( ((byte3 << 3) & 0x18) | ((byte4 >> 5) & 0x07) )] | |
encodedByte5 = alphabet[Int( ((byte3 >> 2) & 0x1F) )] | |
fallthrough | |
case 3: | |
encodedByte4 = alphabet[Int( ((byte2 << 1) & 0x1E) | ((byte3 >> 7) & 0x01) )] | |
fallthrough | |
case 2: | |
encodedByte2 = alphabet[Int( ((byte1 >> 1) & 0x1F) )] | |
encodedByte3 = alphabet[Int( ((byte1 << 4) & 0x10) | ((byte2 >> 4) & 0x0F) )] | |
fallthrough | |
case 1: | |
encodedByte0 = alphabet[Int( ((byte0 >> 3) & 0x1F) )] | |
encodedByte1 = alphabet[Int( ((byte0 << 2) & 0x1C) | ((byte1 >> 6) & 0x03) )] | |
fallthrough | |
default: | |
break | |
} | |
result += encodedByte0 + encodedByte1 + encodedByte2 + encodedByte3 + encodedByte4 + encodedByte5 + encodedByte6 + encodedByte7 | |
} | |
return result | |
} | |
func Base32Decode(data: String, alphabet: Array<Int>, characters: Array<String>) -> NSData? { | |
var processingData = "" | |
for char in data.uppercaseString { | |
let str = String(char) | |
if contains(characters, str) { | |
processingData += str | |
} else if !contains(characters, str) && str != "=" { | |
return nil | |
} | |
} | |
if let base32Data = processingData.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false) { | |
// how much space do we need | |
let fullGroups = base32Data.length / 8 | |
var bytesInPartialGroup: Int = 0 | |
switch base32Data.length % 8 { | |
case 0: | |
bytesInPartialGroup = 0 | |
case 2: | |
bytesInPartialGroup = 1 | |
case 4: | |
bytesInPartialGroup = 2 | |
case 5: | |
bytesInPartialGroup = 3 | |
case 7: | |
bytesInPartialGroup = 4 | |
default: | |
return nil | |
} | |
let totalNumberOfBytes = fullGroups * 5 + bytesInPartialGroup | |
// allocate a buffer big enough for our decode | |
let buffer = UnsafeMutablePointer<UInt8>.alloc(totalNumberOfBytes) | |
let base32Bytes = UnsafePointer<UInt8>(base32Data.bytes) | |
var decodedByteIndex = 0; | |
for byteIndex in stride(from: 0, to: base32Data.length, by: 8) { | |
let maxOffset = (byteIndex + 8 >= base32Data.length) ? base32Data.length : byteIndex + 8 | |
let numberOfBytes = maxOffset - byteIndex | |
var encodedByte0: UInt8 = 0 | |
var encodedByte1: UInt8 = 0 | |
var encodedByte2: UInt8 = 0 | |
var encodedByte3: UInt8 = 0 | |
var encodedByte4: UInt8 = 0 | |
var encodedByte5: UInt8 = 0 | |
var encodedByte6: UInt8 = 0 | |
var encodedByte7: UInt8 = 0 | |
switch numberOfBytes { | |
case 8: | |
encodedByte7 = UInt8(alphabet[Int( base32Bytes[byteIndex + 7] )]) | |
fallthrough | |
case 7: | |
encodedByte6 = UInt8(alphabet[Int( base32Bytes[byteIndex + 6] )]) | |
fallthrough | |
case 6: | |
encodedByte5 = UInt8(alphabet[Int( base32Bytes[byteIndex + 5] )]) | |
fallthrough | |
case 5: | |
encodedByte4 = UInt8(alphabet[Int( base32Bytes[byteIndex + 4] )]) | |
fallthrough | |
case 4: | |
encodedByte3 = UInt8(alphabet[Int( base32Bytes[byteIndex + 3] )]) | |
fallthrough | |
case 3: | |
encodedByte2 = UInt8(alphabet[Int( base32Bytes[byteIndex + 2] )]) | |
fallthrough | |
case 2: | |
encodedByte1 = UInt8(alphabet[Int( base32Bytes[byteIndex + 1] )]) | |
fallthrough | |
case 1: | |
encodedByte0 = UInt8(alphabet[Int( base32Bytes[byteIndex + 0] )]) | |
fallthrough | |
default: | |
break; | |
} | |
buffer[decodedByteIndex + 0] = ((encodedByte0 << 3) & 0xF8) | ((encodedByte1 >> 2) & 0x07) | |
buffer[decodedByteIndex + 1] = ((encodedByte1 << 6) & 0xC0) | ((encodedByte2 << 1) & 0x3E) | ((encodedByte3 >> 4) & 0x01) | |
buffer[decodedByteIndex + 2] = ((encodedByte3 << 4) & 0xF0) | ((encodedByte4 >> 1) & 0x0F) | |
buffer[decodedByteIndex + 3] = ((encodedByte4 << 7) & 0x80) | ((encodedByte5 << 2) & 0x7C) | ((encodedByte6 >> 3) & 0x03) | |
buffer[decodedByteIndex + 4] = ((encodedByte6 << 5) & 0xE0) | (encodedByte7 & 0x1F) | |
decodedByteIndex += 5 | |
} | |
return NSData(bytesNoCopy: buffer, length: totalNumberOfBytes, freeWhenDone: true) | |
} | |
return nil | |
} | |
extension String { | |
var base32EncodedString: String? { | |
get { | |
if let data = (self as NSString).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) { | |
return Base32Encode(data) | |
} else { | |
return nil | |
} | |
} | |
} | |
var base32DecodedData: NSData? { | |
get { | |
return Base32Decode(self) | |
} | |
} | |
func base32DecodedString(encoding: NSStringEncoding = NSUTF8StringEncoding) -> String? { | |
if let data = self.base32DecodedData { | |
return NSString(data: data, encoding: encoding) as String | |
} else { | |
return nil | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated to Swift 3 here: https://gist.github.com/troupmar/b5bf94be41108a905fcc6a8d09031ced