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.
Related
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()
}
}
I am using amazon product advertising api for search product. Installed awscore and alamofire cocopods. Done functionality for getting signature and added parameters for item search to get product images, title and description in table view list.
Here is the code i tried for getting amazon search:
private func signedParametersForParameters(parameters: [String: String]) -> [String: String] {
let sortedKeys = Array(parameters.keys).sorted(by: <)
let query = sortedKeys.map { String(format: "%#=%#", $0, parameters[$0] ?? "") }.joined(separator: "&")
let stringToSign = "GET\nwebservices.amazon.in\n/onca/xml\n\(query)"
print("stringToSign::::\(stringToSign)")
let dataToSign = stringToSign.data(using: String.Encoding.utf8)
let signature = AWSSignatureSignerUtility.hmacSign(dataToSign, withKey: CameraViewController.kAmazonAccessSecretKey, usingAlgorithm: UInt32(kCCHmacAlgSHA256))!
var signedParams = parameters;
signedParams["Signature"] = urlEncode(signature)
print("urlencodesignature::\(urlEncode(signature))")
return signedParams
}
public func urlEncode(_ input: String) -> String {
let allowedCharacterSet = (CharacterSet(charactersIn: "!*'();:#&=+$,/?%#[] ").inverted)
if let escapedString = input.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) {
return escapedString
}
return ""
}
func send(url: String) -> String {
// activityIndicator.startAnimating()
guard let url = URL(string: url) else {
print("Error! Invalid URL!") //Do something else
// activityIndicator.stopAnimating()
return ""
}
print("send URL: \(url)")
let request = URLRequest(url: url)
let semaphore = DispatchSemaphore(value: 0)
var data: Data? = nil
URLSession.shared.dataTask(with: request) { (responseData, _, _) -> Void in
data = responseData
print("send URL session data: \(String(describing: data))")
let parser = XMLParser(data: data!)
parser.delegate = self as? XMLParserDelegate
if parser.parse() {
print(self.results ?? "No results")
}
semaphore.signal()
}.resume()
// activityIndicator.stopAnimating()
semaphore.wait(timeout: .distantFuture)
let reply = data.flatMap { String(data: $0, encoding: .utf8) } ?? ""
return reply
}
public func getSearchItem(searchKeyword: String) -> [String:AnyObject]{
let timestampFormatter: DateFormatter
timestampFormatter = DateFormatter()
timestampFormatter.timeZone = TimeZone(identifier: "GMT")
timestampFormatter.dateFormat = "YYYY-MM-dd'T'HH:mm:ss'Z'"
timestampFormatter.locale = Locale(identifier: "en_US_POSIX")
// let responsegroupitem: String = "ItemAttributes"
// let responsegroupImages:String = "Images"
// activityIndicator.startAnimating()
let operationParams: [String: String] = [
"Service": "AWSECommerceService",
"Operation": "ItemSearch",
"ResponseGroup": "Images,ItemAttributes",
"IdType": "ASIN",
"SearchIndex":"All",
"Keywords": searchKeyword,
"AWSAccessKeyId": urlEncode(CameraViewController.kAmazonAccessID),
"AssociateTag": urlEncode(CameraViewController.kAmazonAssociateTag),
"Timestamp": urlEncode(timestampFormatter.string(from: Date()))]
let signedParams = signedParametersForParameters(parameters: operationParams)
let query = signedParams.map { "\($0)=\($1)" }.joined(separator: "&")
let url = "http://webservices.amazon.in/onca/xml?" + query
print("querydata::::\(query)")
let reply = send(url: url)
print("reply::::\(reply)")
// activityIndicator.stopAnimating()
return [:]
}
Created bridging header file #import .
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
getSearchItem(searchKeyword: searchKeyword)
}
Here is my console output:
My issue is when tapping search button product searched was not listing. What mistake done i don't know. Can anyone help me out of this pls..
According to the documentation:
The HTTPRequestURI component is the HTTP absolute path component of the URI up to, but not including, the query string. If the HTTPRequestURI is empty, use a forward slash ( / ).
HTTPRequestURI is always "/onca/xml" for Product Advertising API. HTTPVerb is either GET or POST.
Try just setting requestURL to "/onca/xml" instead of the full URL you shouldn't be sending the full URL or the query string in this part.
Also you need to percent encode the values that you are sending. You are sending commas in the response group property which should be percent encoded
let operationParams: [String: String] = [
"Service": "AWSECommerceService",
"Operation": "ItemSearch",
"ResponseGroup": urlEncode("Images,ItemAttributes"),
"IdType": "ASIN",
"SearchIndex":"All",
"Keywords": urlEncode(searchKeyword),
"AWSAccessKeyId": urlEncode(CameraViewController.kAmazonAccessID),
"AssociateTag": urlEncode(CameraViewController.kAmazonAssociateTag),
"Timestamp": urlEncode(timestampFormatter.string(from: Date()))]
let stringToSign = "GET\n/onca/xml\n\(query)"
Note: You should be using https instead of http
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)
What I have to is just let user pick photo, upload it on server and then decode back and display it. What I am doing now is encode image and then pass it to a model as Base64. I store it as bytea in PosgtgreSQL.
let imageb: NSData = UIImageJPEGRepresentation(image, 0.7)! as NSData
let dataDecoded: String = imageb.base64EncodedString(options: .lineLength64Characters)
let imageStr: String = dataDecoded.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
then inside my model I have
private var JSON: [String: Any] {
get {
return ["data": self.imageData]
}
}
then I post it on server using Alamofire
APILayer.shared.request(parameters: self.JSON, url: "photo/create", method: .post) { responce in
//some handling stuff
}
server side client gateway method
let photos = user.getPhotos()
try! response.setBody(json: PhotoDocument.jsonFrom(array: photos))
object methods
func getPhotos() -> [PhotoDocument] {
return PhotoDocumentMapper.search(id: self.id)
}
private var JSON: [String: Any] {
get {
return ["description": self.description, "importancy": self.importancy, "date": self.date, "data": self.imageData, "id": self.id]
}
}
class func jsonFrom(array: [PhotoDocument]) -> [String: Any] {
var jsons: [Any] = []
for photo in array {
jsons.append(photo.JSON)
}
return ["photos" : jsons]
}
datamapper method
class func search(id: Int) -> [PhotoDocument] {
let p = PGConnection()
let _ = p.connectdb("host=localhost port=5432 dbname=perfect")
let result = p.exec(statement: "select * from \"Photos\" where \"userId\" = $1", params: [id])
p.close()
var photos: [PhotoDocument] = []
let resultsNumber = result.numTuples() - 1
if resultsNumber != -1 {
for index in 0...resultsNumber {
let id = result.getFieldInt(tupleIndex: index, fieldIndex: 0)!
let description = result.getFieldString(tupleIndex: index, fieldIndex: 4)!
let date = result.getFieldString(tupleIndex: index, fieldIndex: 5)!
let imageData = result.getFieldString(tupleIndex: index, fieldIndex: 3)!
let importancy = result.getFieldInt(tupleIndex: index, fieldIndex: 2)!
let userId = result.getFieldInt(tupleIndex: index, fieldIndex: 1)!
let photo = PhotoDocument(userId: userId, description: description, date: date, id: id, imageData: imageData, importancy: importancy)
photos.append(photo)
}
}
return photos
}
then I receive all this data, and I receive huge String and try this, but it crashes on the first line
let dataDecoded: NSData = NSData(base64Encoded: photo.imageData, options: .ignoreUnknownCharacters)! //crash here
let decodedimage = UIImage(data: dataDecoded as Data)
self.test.image = decodedimage
What am I doing wrong? How can I store UIImage as Base64String as bytea of PostgreSQL?
So what I had to do is remove this line while encoding
let imageStr: String = dataDecoded.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
and change PostgreSQL field to be text and not bytea
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")
}