I have to convert string to sha1 and then use base64. Simply base64_encode(sha1(My_String)). I want to do that but I can't fix it correctly. I can convert SHA1 with that code: let firstTry = SHA1.hash(from: "call") but when I try to make it in base64 it gave error which is say string not allowed. How can I convert base64?
Thanks for your attention.
I try to conver c[all] to sha1 with that code :
let str = "c[all]"
let den3 = str.sha1()
its working good and return correct which is : 0fee061faab109e27b75010f2f1a0d8258bab7c5
And when I add let den3 = str.sha1().toBase64() I get MGZlZTA2MWZhYWIxMDllMjdiNzUwMTBmMmYxYTBkODI1OGJhYjdjNQ== which is wrong actually I need to get that: D+4GH6qxCeJ7dQEPLxoNgli6t8U=
Where is my issue?
Here my extensions
extension String {
func sha1() -> String {
let data = Data(self.utf8)
var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
data.withUnsafeBytes {
_ = CC_SHA1($0.baseAddress, CC_LONG(data.count), &digest)
}
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return hexBytes.joined()
}
func toBase64() -> String {
return Data(self.utf8).base64EncodedString()
}
}
You could use CryptoKit like this
import CryptoKit
let str: String = "Hello, world!"
//Get the SHA1 hash
let hash = Insecure.SHA1.hash(data: str.data(using: .utf8)!)
//Get string representation of the hash (matches hash.description)
let hashedString = hash.map({ String(format: "%02hhx", $0) }).joined()
//Get the base64 string
let encodedString = hashedString.data(using: .utf8)!.base64EncodedString()
On iOS 13+, you can use CryptoKit as follows:
import CryptoKit
extension String {
func base64EncodedSHA1Hash(using encoding: Encoding = .utf8) -> String? {
guard let data = data(using: encoding) else { return nil }
let hash = Data(Insecure.SHA1.hash(data: data))
return hash.base64EncodedString()
}
}
Related
I have a byte array and want to sign it with an Asymmetric private key in Swift code. I have java code below and want same thing in iOS swift.
try {
final java.security.Signature instance = provider == null ?
java.security.Signature.getInstance(algorithm.getJvmName()) :
java.security.Signature.getInstance(algorithm.getJvmName(), provider);
if (signature.getParameterSpec() != null) {
instance.setParameter(signature.getParameterSpec());
}
instance.initSign(key);
instance.update(signingStringBytes);
return instance.sign();
} catch (final NoSuchAlgorithmException e) {
throw new UnsupportedAlgorithmException(algorithm.getJvmName());
} catch (final Exception e) {
throw new IllegalStateException(e);
}
Tried the below code in Swift
public func sign(value: String, base64EncodingOptions:Data.Base64EncodingOptions = []) -> String? {
do {
let keyData = Data(base64Encoded: privateKey)!
let key = SecKeyCreateWithData(keyData as CFData,
[kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPrivate,] as NSDictionary, nil)!
var data = value.data(using: .utf8)!
var error: Unmanaged<CFError>?
guard let signedData = SecKeyCreateSignature(key, .rsaSignatureDigestPSSSHA256, data as CFData, &error) as Data?
else {
return nil
}
let signData = signedData as Data
let signedString = signData.base64EncodedString(options: [])
return signedString
}
catch {
//handle error
}
return ""
}
I am using this method to sign a session key:
func signature(sessionKeyBase64: String, privateKey: String) throws -> String? {
let sk = try extractSessionKey(encryptedSessionKeyBase64: sessionKeyBase64)
let privateKeyDer = try SwKeyConvert.PrivateKey.pemToPKCS1DER(privateKey)
let signature = try? CC.RSA.sign(sk, derKey: privateKeyDer, padding: .pkcs15, digest: .sha256, saltLen: 0);
return signature?.base64EncodedString()
}
func extractSessionKey(encryptedSessionKeyBase64: String, privateKey: String) throws -> Data {
let privateKeyDer = try SwKeyConvert.PrivateKey.pemToPKCS1DER(privateKey)
let encryptedData = Data(base64Encoded: encryptedSessionKeyBase64)!
return try CC.RSA.decrypt(encryptedData, derKey: privateKeyDer, tag: Data(), padding: .pkcs1, digest: .sha1).0
}
and a below method to check a signature:
func isVerified(encryptedKeyBase64: String, signatureBase64: String, signerPublicKeyBase64: String) throws -> Bool {
let sk = try extractSessionKey(encryptedSessionKeyBase64: encryptedKeyBase64)
let pk = try SwKeyConvert.PublicKey.pemToPKCS1DER(signerPublicKeyBase64)
let signatureBytes = Data(base64Encoded: signatureBase64)
return (try? CC.RSA.verify( sk, derKey: pk, padding: .pkcs15, digest: .sha256, saltLen: 0, signedData: signatureBytes!))!
}
with the help of the third party library SwCrypt
I work with corporate date which must be protected.
I have data for example:
let userName = String()
let password = String()
let profileImage = UIImage()
So this data i want to encrypt this data and send to server.
Important: to decrypt i want to use special key which will store at the app?
So it's possible to do this?
For string the Encryption and Decryption can be done using RNCryptor.
import Foundation
import RNCryptor
extension String {
func encrypt(encryptionKey: String) -> String {
let messageData = self.data(using: .utf8)!
let cipherData = RNCryptor.encrypt(data: messageData, withPassword: encryptionKey)
return cipherData.base64EncodedString()
}
func decrypt(encryptionKey: String) -> String? {
let encryptedData = Data.init(base64Encoded: self)!
if let value = try? RNCryptor.decrypt(data: encryptedData, withPassword: encryptionKey) {
let decryptedString = String(data: value, encoding: .utf8)!
return decryptedString
} else{
return nil
}
}
}
Usage:-
let encyptionKey = "password"
let unencriptedMessage = "Hello World"
print (unencriptedMessage)
let encryptedMessage = unencriptedMessage.encrypt(encryptionKey: encyptionKey)
print (encryptedMessage)
if let decryptedMessage = encryptedMessage.decrypt(encryptionKey: encyptionKey) {
print (decryptedMessage)
}
Output:-
Similar Answer
Hope this Helps. Happy Coding.
It's now easier with Swift 4 to encode / decode to and from JSON or Properties list.
But I can't find how to encode to Data using Codable, without using Objective-C methods initWithCoder and encodeWithCoder.
Considering this simple class:
struct Question: Codable {
var title: String
var answer: Int
var question: Int
}
How can I encode it to Data using CodingKeys and not initWithCoder and encodeWithCoder?
EDIT:
I also need to be able to deserialize objects previously saved in userdefaults using NSKeyedArchiver.
Well, you no longer need NSKeyedArchiver.
Try this:
let questionObj = Question(title: "WWDC, 2017", answer: 1,question:1)
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(questionObj) {
UserDefaults.standard.set(encoded, forKey: "K_Question")
}
let decoder = JSONDecoder()
if let questionData = UserDefaults.standard.data(forKey: "K_Question"),
let question = try? decoder.decode(Question.self, from: questionData) {
print(question.title)
print(question.answer)
print(question.question)
}
Swift 5: a great simple extension for UserDefaults:
extension UserDefaults {
func save<T: Codable>(_ object: T, forKey key: String) {
let encoder = JSONEncoder()
if let encodedObject = try? encoder.encode(object) {
UserDefaults.standard.set(encodedObject, forKey: key)
UserDefaults.standard.synchronize()
}
}
func getObject<T: Codable>(forKey key: String) -> T? {
if let object = UserDefaults.standard.object(forKey: key) as? Data {
let decoder = JSONDecoder()
if let decodedObject = try? decoder.decode(T.self, from: object) {
return decodedObject
}
}
return nil
}
}
Usage
save
UserDefaults.standard.save(currentUser, forKey: "currentUser")
get
let user: User? = UserDefaults.standard.getObject(forKey: "currentUser")
Well it can be achieved via JSONEncoder and JSONDecoder.
struct Question: Codable {
var title: String
var answer: Int
var question: Int
}
let questionObj = Question(title: "Swift", answer: "Open Source",question:1)
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(questionObj) {
if let json = String(data: encoded, encoding: .utf8) {
print(json)
}
let decoder = JSONDecoder()
if let decoded = try? decoder.decode(Question.self, from: encoded) {
print(decoded)
}
}
struct Question: Codable {
var title: String
var answer: Int
var question: Int
}
class UserDefaults_Question {
static let key = "myapp.trick.question"
static var value: UserDefaults_Question? {
get {
guard let data = UserDefaults.standard.data(forKey: key) else {
print("no model for key: \(key)")
return nil
}
guard let model = try? JSONDecoder().decode(UserDefaults_Question.self, from: data) else {
print("failed to decode model for key: \(key)")
return nil
}
print("did load model for key: \(key)")
return model
}
set {
guard let value = newValue, let data: Data = try? JSONEncoder().encode(value) else {
print("removing model for key: \(key)")
UserDefaults.standard.removeObject(forKey: key)
return
}
print("inserting model for key: \(key)")
UserDefaults.standard.set(data, forKey: key)
}
}
}
UserDefaults_Question.value = Question(title: "Next President", answer: 666, question: -1)
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), UnsafeMutablePointer(res!.mutableBytes))
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
}
I am using this function to encrypt strings it was working fine in swift 2,
now its not working in swift 3.0
Perfect solution Swift 3+:
extension String {
// MARK: - SHA256
func get_sha256_String() -> String {
guard let data = self.data(using: .utf8) else {
print("Data not available")
return ""
}
return getHexString(fromData: digest(input: data as NSData))
}
private func digest(input : NSData) -> NSData {
let digestLength = Int(CC_SHA256_DIGEST_LENGTH)
var hashValue = [UInt8](repeating: 0, count: digestLength)
CC_SHA256(input.bytes, UInt32(input.length), &hashValue)
return NSData(bytes: hashValue, length: digestLength)
}
private func getHexString(fromData data: NSData) -> String {
var bytes = [UInt8](repeating: 0, count: data.length)
data.getBytes(&bytes, length: data.length)
var hexString = ""
for byte in bytes {
hexString += String(format:"%02x", UInt8(byte))
}
return hexString
}
}
How to use:
let desiredSHA256 = "yourString".get_sha256_String()
func sha256(string: String) -> Data? {
guard let messageData = string.data(using:String.Encoding.utf8) else { return nil; }
var digestData = Data(count: Int(CC_SHA256_DIGEST_LENGTH))
_ = digestData.withUnsafeMutableBytes {digestBytes in
messageData.withUnsafeBytes {messageBytes in
CC_SHA256(messageBytes, CC_LONG(messageData.count), digestBytes)
}
}
return digestData
}
Example:
let testString = "sha me"
print("testString: \(testString)")
let shaData = sha256(string: testString)
let shaHex = shaData!.map { String(format: "%02hhx", $0) }.joined()
print("shaHex: \(shaHex)")
Output:
testString: sha me
shaData: a60e0eee 30a3a4f1 c4f8b93f 16ad22cb 0339447b 1653f331 edbda55f eee00789
What is new is the .withUnsafeMutableBytes closure.
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
}
Replaced CC_SHA256((data! as NSData).bytes, CC_LONG(data!.count), UnsafeMutablePointer(res!.mutableBytes))
in my iOS project I need to save an entire JSON as user data and then reload it on next app launch.
Squashing it into many values and then recreate the JSON is not an option, I just need some serializable way of saving the entire raw JSON.
I tried to convert it to String by doing json.rawString() and recreate it by passing the obtained string to JSON(string), but it doesn't work.
I'm both astonished by the difficulty of making such a simple thing and by the lack of informations about a thing like this online, so I can not wait to discover how to do that :)
Example:
public func saveJSON(j: JSON) {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setValue(j.rawString()!, forKey: "json")
// here I save my JSON as a string
}
public func loadJSON() -> JSON {
let defaults = NSUserDefaults.standardUserDefaults()
return JSON(defaults.valueForKey("json") as! String))
// here the returned value doesn't contain a valid JSON
}
Thank you for your answers but they didn't solve my problem. I finally found the solution, which was really simple in facts:
public func loadJSON() -> JSON {
let defaults = NSUserDefaults.standardUserDefaults()
return JSON.parse(defaults.valueForKey("json") as! String))
// JSON from string must be initialized using .parse()
}
Really simple but not documented well.
Swift 5+
func saveJSON(json: JSON, key:String){
if let jsonString = json.rawString() {
UserDefaults.standard.setValue(jsonString, forKey: key)
}
}
func getJSON(_ key: String)-> JSON? {
var p = ""
if let result = UserDefaults.standard.string(forKey: key) {
p = result
}
if p != "" {
if let json = p.data(using: String.Encoding.utf8, allowLossyConversion: false) {
do {
return try JSON(data: json)
} catch {
return nil
}
} else {
return nil
}
} else {
return nil
}
}
Use this if you using SwiftyJSON.
I used the following code and it works like a charm!
NSString *json = #"{\"person\":{\"first_name\":\"Jim\", \"last_name\":\"Bell\"}} ";
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"json"]== nil){
[defaults setObject:json forKey:#"json"];
//[defaults synchronize];
}
else{
NSLog(#"JSON %#", [defaults objectForKey:#"json"]);
}
First try to see whether you can save a hard-coded string to the NSUserDefaults first.
Also try to call a [defaults synchronize]; call when you want to save the data. Although that is NOT required, it might be needed in extreme conditions such as if the app is about to terminate.
to retrieve from UserDefaults
func get(_ key: String)-> JSON? {
if let standard = UserDefaults.standard.data(forKey: key), let data = try? standard.toData() {
return JSON(data)
} else {
return nil
}
}
You should parse everything to Data, in order to save model (Better from JSON / JSONSerialization) to UserDefaults
Coded In Swift 5.x
Swift 4+
A cleaner version to the one provided by Alfi up above, for any else that might need this.
func addUserJSONDataToUserDefaults(userData: JSON) {
guard let jsonString = userData.rawString() else { return }
userDefaults.set(jsonString, forKey: "user")
}
func getCachedUserJSONData() -> JSON? {
let jsonString = userDefaults.string(forKey: "user") ?? ""
guard let jsonData = jsonString.data(using: .utf8, allowLossyConversion: false) else { return nil }
return try? JSON(data: jsonData)
}
Here's a swift example that works
import SwiftyJSON
class Users{
init(){
let yourJSON = {"name":"Deeznuts"}
let response = JSON(yourJSON)
// Store your
let httpMessage = response["name"].stringValue
}
}
I extended Userdefaults and added a new var for easy usage and consistency of my keys.
Here is my code:
extension UserDefaults {
var downloadedMarkersInfo : JSON? {
get {
if let jsonString = defaults.value(forKey: "markers") as? String {
if let json = jsonString.data(using: String.Encoding.utf8, allowLossyConversion: false) {
return try! JSON(data: json)
}
}
return nil
}
set {
if let json = newValue {
let jsonString = json.rawString()!
defaults.setValue(jsonString, forKey: "markers")
}
}
}
}
The usage in my View Controller:
if let jsonData = defaults.downloadedMarkersInfo {
// Your code here.
}
using SwiftyJSON - SWIFT 5
var data = JSON()
if(CustomDefaults().checkObject(key: "list2")){
data = JSON.init(parseJSON: CustomDefaults().getObject(key: "list2") as? String ?? "")
}
else{
var bomb = [JSON]()
bomb.append(["name":"Happy","url":"google.com"])
let finalData = JSON(bomb).rawString() ?? "" //data.rawString() ?? ""
CustomDefaults().setObject(value: finalData, key: "list2")
}