Decoding Base64 in Swift Returns nil - swift

I have been trying to implement Coinbase API in my application that is built using swift 5 and xcode. Whenever I try to convert this base64 encoded data to Normal string, it returns nil.
Here is the string
fI5GtCKFF+O8j8uJlJVGxIvolVUUrVMT9GBouxlpEOUXmaGbwQvHt0z8kK0fUwQaKa45KUOLWHP/CQaM70bhdQ==
Below are the answers i've tried
extension String {
func base64Encoded() -> String? {
return data(using: .utf8)?.base64EncodedString()
}
func base64Decoded() -> String? {
var st = self;
print(st.count)
let remainder = self.count % 4
if remainder > 0 {
st = self.padding(toLength: self.count + 4 - remainder,
withPad: "=",
startingAt: 0)
}
print(st.count)
guard let d = Data(base64Encoded: st, options: .ignoreUnknownCharacters) else{
return nil
}
return String(data: d, encoding: .utf8)
}
}
THE DIFFERENCE
let base64Decoded = Data(base64Encoded: "fI5GtCKFF+O8j8uJlJVGxIvolVUUrVMT9GBouxlpEOUXmaGbwQvHt0z8kK0fUwQaKa45KUOLWHP/CQaM70bhdQ==")!
let sign = HMAC.sign(data: "1".toData()!, algorithm: .sha256, key: base64Decoded)
let signData = sign.base64EncodedString()
The result i receive: vBZ+Z63rFqNmU61yrd91PGQB8f1iqocWkLlAev5XJOc=
It's different from: https://www.liavaag.org/English/SHA-Generator/HMAC/
Link to result There's is the correct output. What am i missing or doing wrong ?

Related

Swift / Apple Sign In - Type HASH256 has no member hash

Issue: "Type HASH256 has no member hash"
Background: Trying to implement Apple sign in with Firebase on Swift
Tried to resolve the issue with the following:
-all pods update
-import CommonCrypto + import CryptoKit
-clean build folder / build
The error is still present
// Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce
private func randomNonceString(length: Int = 32) -> String {
precondition(length > 0)
let charset: Array<Character> =
Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
var result = ""
var remainingLength = length
while remainingLength > 0 {
let randoms: [UInt8] = (0 ..< 16).map { _ in
var random: UInt8 = 0
let errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random)
if errorCode != errSecSuccess {
fatalError("Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)")
}
return random
}
randoms.forEach { random in
if length == 0 {
return
}
if random < charset.count {
result.append(charset[Int(random)])
remainingLength -= 1
}
}
}
return result
}
//Start Apple's sign-in flow
// Unhashed nonce.
fileprivate var currentNonce: String?
#available(iOS 13, *)
func startSignInWithAppleFlow() {
let nonce = randomNonceString()
currentNonce = nonce
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
request.nonce = sha256(nonce)
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self as! ASAuthorizationControllerDelegate
authorizationController.presentationContextProvider = self as! ASAuthorizationControllerPresentationContextProviding
authorizationController.performRequests()
}
#available(iOS 13, *)
private func sha256(_ input: String) -> String {
let inputData = Data(input.utf8)
let hashedData = SHA256.hash(data: inputData)
let hashString = hashedData.compactMap {
return String(format: "%02x", $0)
}.joined()
return hashString
}
// func SHA256() -> String {
//
// let data = self.data(using: String.Encoding.utf8)
// let res = NSMutableData(length: Int(CC_SHA256_DIGEST_LENGTH))
// CC_SHA256(((data! as NSData)).bytes, CC_LONG(data!.count), res?.mutableBytes.assumingMemoryBound(to: UInt8.self))
// let hashedString = "\(res!)".replacingOccurrences(of: "", with: "").replacingOccurrences(of: " ", with: "")
// let badchar: CharacterSet = CharacterSet(charactersIn: "\"<\",\">\"")
// let cleanedstring: String = (hashedString.components(separatedBy: badchar) as NSArray).componentsJoined(by: "")
// return cleanedstring
//
// }
}
//Apple extension
#available(iOS 13.0, *)
extension AuthViewController: ASAuthorizationControllerDelegate {
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
guard let nonce = currentNonce else {
fatalError("Invalid state: A login callback was received, but no login request was sent.")
}
guard let appleIDToken = appleIDCredential.identityToken else {
print("Unable to fetch identity token")
return
}
guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
print("Unable to serialize token string from data: \(appleIDToken.debugDescription)")
return
}
// Initialize a Firebase credential.
let credential = OAuthProvider.credential(withProviderID: "apple.com",
idToken: idTokenString,
accessToken: nonce)
// Sign in with Firebase.
Auth.auth().signIn(with: credential) { (authResult, error) in
if (error != nil) {
// Error. If error.code == .MissingOrInvalidNonce, make sure
// you're sending the SHA256-hashed nonce as a hex string with
// your request to Apple.
print(error?.localizedDescription)
return
}
// User is signed in to Firebase with Apple.
// ...
}
}
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
// Handle error.
print("Sign in with Apple errored: \(error)")
}
}
Image of error
I encountered the same problem, I spend two days figured it out!
The reason is we mistaken installed 'CryptoKit' in our Podfile. which apple also has a build-in 'CryptoKit' for iOS version 13+.
Solution :
1.deleted pod ''CryptoKit' in our pod file.
2. pod install
after that, we will use apple build in 'CryptoKit' which has the build-in method hash.
This should work: add this outside of your class and then instead of request.nonce = sha256(nonce), type request.nonce = nonce.sha256()
extension String {
func sha256() -> String{
if let stringData = self.data(using: String.Encoding.utf8) {
return hexStringFromData(input: digest(input: stringData as NSData))
}
return ""
}
private func digest(input : NSData) -> NSData {
let digestLength = Int(CC_SHA256_DIGEST_LENGTH)
var hash = [UInt8](repeating: 0, count: digestLength)
CC_SHA256(input.bytes, UInt32(input.length), &hash)
return NSData(bytes: hash, length: digestLength)
}
private func hexStringFromData(input: NSData) -> String {
var bytes = [UInt8](repeating: 0, count: input.length)
input.getBytes(&bytes, length: input.length)
var hexString = ""
for byte in bytes {
hexString += String(format:"%02x", UInt8(byte))
}
return hexString
}
}
credit

Unexpectedly nil hashing a password

I'm trying to hash a password with SHA256 method:
class CryptoHandler {
static func sha256(_ str: String) -> String? {
let data = str.data(using: String.Encoding.utf8)
let shaData = sha256(data!)
let rc = String(data: shaData, encoding: String.Encoding.utf8) as String?
return rc
}
static func sha256(_ data: Data) -> Data { var res = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)); data.withUnsafeBytes { _ = CC_SHA256($0, CC_LONG(data.count), &res) }; return Data(bytes: res) }
static func getHashedPassword (pwd: String) -> String{
let hash = sha256(pwd)
return hash!
}
}
When I try to execute getHashedPassword ("0123456789") I have the following error in return hash! line:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an
Optional value
Why this happens? How I can solve it?
The crash occurs because you cannot create a String from encrypted Data. You have to use base64 or hex representation.
This code creates a hex encoded string and doesn't use optionals at all.
class CryptoHandler {
static func sha256(_ str: String) -> String {
let data = Data(str.utf8)
let shaData = sha256(data)
return shaData.hexString
}
static func sha256(_ data: Data) -> Data {
var res = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH));
data.withUnsafeBytes { _ = CC_SHA256($0, CC_LONG(data.count), &res) };
return Data(bytes: res)
}
static func getHashedPassword (pwd: String) -> String{
let hash = sha256(pwd)
return hash
}
}
extension Data {
var hexString : String {
return self.map{ String(format:"%02x", $0) }.joined()
}
}
CryptoHandler.getHashedPassword(pwd:"0123456789")
let rc = String(data: shaData, encoding: String.Encoding.utf8) as String?
will return nil value and you are forcing to compiler a value using return hash! Exclamation mark at the end of hash constant in getHashedPassword method.
You can fix it by modifying getHashedPassword method by accepting an optional value
ex:
static func getHashedPassword (pwd: String) -> String?
{
let hash = sha256(pwd)
return hash
}

How to convert a numeric character reference to a decimal in Swift?

How to convert this type of string "8.37" to its decimal value 8.37?
I'm using Swift 4.
I tried:
extension String {
func hexToFloat() -> Float {
var toInt = Int32(truncatingIfNeeded: strtol(self, nil, 16))
var float:Float32!
memcpy(&float, &toInt, MemoryLayout.size(ofValue: float))
return float
}
}
[...]
let myString = "8.37"
let myDecimal = myString.hexToFloat()
print(myDecimal) // prints 0.0
(From here)
There's no straight forward way (at least to my knowledge). But you can do something like below to get the value. Please note that the code below is in Swift 3. You may have to change the syntax.
extension String {
func hexToFloat() -> Float {
let data = myString.data(using: .utf8)
let options: [String: Any] = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
do {
let attributedString = try NSAttributedString(data: data!, options: options, documentAttributes: nil)
return Float(attributedString.string)!
} catch {
return 0
}
}
}
let myString = "8.37"
let myDecimal = myString.hexToFloat()
print(myDecimal) // prints 8.37

Hex string to text conversion - swift 3

I'm trying to convert an hex string to text.
This is what i have:
// Str to Hex
func strToHex(text: String) -> String {
let hexString = text.data(using: .utf8)!.map{ String(format:"%02x", $0) }.joined()
return "0x" + hexString
}
and I'm trying to reverse the hex string that I've just created back to the original one.
So, for example:
let foo: String = strToHex(text: "K8") //output: "0x4b38"
and i would like to do something like
let bar: String = hexToStr(hex: "0x4b38") //output: "K8"
can someone help me?
Thank you
You probably can use something like this:
func hexToStr(text: String) -> String {
let regex = try! NSRegularExpression(pattern: "(0x)?([0-9A-Fa-f]{2})", options: .caseInsensitive)
let textNS = text as NSString
let matchesArray = regex.matches(in: textNS as String, options: [], range: NSMakeRange(0, textNS.length))
let characters = matchesArray.map {
Character(UnicodeScalar(UInt32(textNS.substring(with: $0.rangeAt(2)), radix: 16)!)!)
}
return String(characters)
}
NSRegularExpression is overkill for the job. You can convert the string to byte array by grabbing two characters at a time:
func hexToString(hex: String) -> String? {
guard hex.characters.count % 2 == 0 else {
return nil
}
var bytes = [CChar]()
var startIndex = hex.index(hex.startIndex, offsetBy: 2)
while startIndex < hex.endIndex {
let endIndex = hex.index(startIndex, offsetBy: 2)
let substr = hex[startIndex..<endIndex]
if let byte = Int8(substr, radix: 16) {
bytes.append(byte)
} else {
return nil
}
startIndex = endIndex
}
bytes.append(0)
return String(cString: bytes)
}
Solution that supports also special chars like emojis etc.
static func hexToPlain(input: String) -> String {
let pairs = toPairsOfChars(pairs: [], string: input)
let bytes = pairs.map { UInt8($0, radix: 16)! }
let data = Data(bytes)
return String(bytes: data, encoding: .utf8)!
}

Convert string to base64 in Swift 3

let strsize = 10_000_000
let tries = 100
var longstring:String = "a"
for i in 1...strsize {
longstring += "a"
}
for i in 1..<2 {
let basestring = NSData(base64EncodedString: longstring, options: .IgnoreUnknownCharacters)
print(basestring)
}
Writing a code in command prompt. What is the correct code to write for Swift 3 which I been getting use of unresolved identifier NSData . Most of the tutorials on encoding string to base64 aren't working.
This is working for you on Linux or Mac?
http://studyswift.blogspot.sg/2016/03/convert-nsdatauint8-to-base64-in-swift.html
Use this instead:
let longstring = "test123"
if let data = (longstring).data(using: String.Encoding.utf8) {
let base64 = data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0))
print(base64)// dGVzdDEyMw==\n
}
this string extention can help .
extension String {
//Base64 decode
func fromBase64() -> String? {
guard let data = Data(base64Encoded: self) else {
return nil
}
return String(data: data, encoding: .utf8)
}
//Base64 encode
func toBase64() -> String {
return Data(self.utf8).base64EncodedString()
}
}
how to use.
let str = "Hello World"
str.toBase64().fromBase64()
In Swift 4.2 and Xcode 10.1
//Base64 encoding
let data = combinedString.data(using: .utf8)//Here combinedString is your string
let encodingString = data?.base64EncodedString()
print(encodingString!)
// OR Single line of code
let encodingString = combinedString.data(using: .utf8)?.base64EncodedString()//Here combinedString is your string
print(encodingString!)