Client certificate authentication in swift2 - ssl-certificate

I want to authenticate client certificate in my app. I am getting the following errors in didReceiveChallenge function. I found this solution in this link.
My didReceiveChallenge func code:
func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
if challenge.protectionSpace.authenticationMethod == (NSURLAuthenticationMethodServerTrust) {
let serverTrust:SecTrustRef = challenge.protectionSpace.serverTrust!
let certificate: SecCertificateRef = SecTrustGetCertificateAtIndex(serverTrust, 0)!
let remoteCertificateData = CFBridgingRetain(SecCertificateCopyData(certificate))!
let cerPath: String = NSBundle.mainBundle().pathForResource("example.com", ofType: "cer")!
let localCertificateData = NSData(contentsOfFile:cerPath)!
if (remoteCertificateData.isEqualToData(localCertificateData) == true) {
let credential:NSURLCredential = NSURLCredential(forTrust: serverTrust)
challenge.sender?.useCredential(credential, forAuthenticationChallenge: challenge)
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
} else {
completionHandler(NSURLSessionAuthChallengeDisposition.CancelAuthenticationChallenge, nil)
}
}
else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate
{
let path: String = NSBundle.mainBundle().pathForResource("client", ofType: "p12")!
let PKCS12Data = NSData(contentsOfFile:path)!
var p12items : Unmanaged<CFArray>?
let index: CFIndex = 1
let password: CFString = "password"
var values = [unsafeAddressOf(password)]
var keys = [unsafeAddressOf(kSecImportExportPassphrase)]
var keyCallbacks = kCFTypeDictionaryKeyCallBacks
var valueCallbacks = kCFTypeDictionaryValueCallBacks
let length: CFIndex = PKCS12Data.length
let p12CfData: CFData = CFDataCreate(kCFAllocatorDefault, UnsafePointer<UInt8>(PKCS12Data.bytes), length)
let options = CFDictionaryCreate(kCFAllocatorDefault, &keys, &values, index, &keyCallbacks, &valueCallbacks)
let result = SecPKCS12Import(p12CfData, options, p12items)
if result == noErr {
let idIndex: CFIndex = 0
var items = p12items?.takeRetainedValue()
var identityDict = CFArrayGetValueAtIndex(items!, idIndex)
var keyAddress = unsafeAddressOf(kSecImportItemIdentity)
var identityApp: SecIdentityRef = CFDictionaryGetValue(identityDict, keyAddress)
var certRef : Unmanaged<SecCertificateRef>?
SecIdentityCopyCertificate(identityApp, certRef)
var cert: SecCertificateRef = certRef!.takeRetainedValue()
var certArray = [unsafeAddressOf(cert)]
var arrayCallback = kCFTypeArrayCallBacks
var myCerts: CFArrayRef = CFArrayCreate(kCFAllocatorDefault, &certArray, index, &arrayCallback);
let urlCredential:NSURLCredential = NSURLCredential(
identity: identityApp,
certificates: myCerts as [AnyObject],
persistence: NSURLCredentialPersistence.Permanent)
challenge.sender!.useCredential(urlCredential ,forAuthenticationChallenge:challenge)
}
}
Any example for client authentication in NSURLSession will be helpful.
Thanks in advance.

Following are the code changes which works fine with Self Signed SSL certificate
func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
if challenge.protectionSpace.authenticationMethod == (NSURLAuthenticationMethodServerTrust) {
let serverTrust:SecTrustRef = challenge.protectionSpace.serverTrust!
let certificate: SecCertificateRef = SecTrustGetCertificateAtIndex(serverTrust, 0)!
let remoteCertificateData = CFBridgingRetain(SecCertificateCopyData(certificate))!
let cerPath: String = NSBundle.mainBundle().pathForResource("xyz.com", ofType: "cer")!
let localCertificateData = NSData(contentsOfFile:cerPath)!
if (remoteCertificateData.isEqualToData(localCertificateData) == true) {
let credential:NSURLCredential = NSURLCredential(forTrust: serverTrust)
challenge.sender?.useCredential(credential, forAuthenticationChallenge: challenge)
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
} else {
completionHandler(NSURLSessionAuthChallengeDisposition.CancelAuthenticationChallenge, nil)
}
}
else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate
{
let path: String = NSBundle.mainBundle().pathForResource("client", ofType: "p12")!
let PKCS12Data = NSData(contentsOfFile:path)!
let identityAndTrust:IdentityAndTrust = self.extractIdentity(PKCS12Data);
let urlCredential:NSURLCredential = NSURLCredential(
identity: identityAndTrust.identityRef,
certificates: identityAndTrust.certArray as? [AnyObject],
persistence: NSURLCredentialPersistence.ForSession);
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, urlCredential);
}
else
{
completionHandler(NSURLSessionAuthChallengeDisposition.CancelAuthenticationChallenge, nil);
}
}
struct IdentityAndTrust {
var identityRef:SecIdentityRef
var trust:SecTrustRef
var certArray:AnyObject
}
func extractIdentity(certData:NSData) -> IdentityAndTrust {
var identityAndTrust:IdentityAndTrust!
var securityError:OSStatus = errSecSuccess
let path: String = NSBundle.mainBundle().pathForResource("client", ofType: "p12")!
let PKCS12Data = NSData(contentsOfFile:path)!
let key : NSString = kSecImportExportPassphrase as NSString
let options : NSDictionary = [key : "xyz"]
//create variable for holding security information
//var privateKeyRef: SecKeyRef? = nil
var items : CFArray?
securityError = SecPKCS12Import(PKCS12Data, options, &items)
if securityError == errSecSuccess {
let certItems:CFArray = items as CFArray!;
let certItemsArray:Array = certItems as Array
let dict:AnyObject? = certItemsArray.first;
if let certEntry:Dictionary = dict as? Dictionary<String, AnyObject> {
// grab the identity
let identityPointer:AnyObject? = certEntry["identity"];
let secIdentityRef:SecIdentityRef = identityPointer as! SecIdentityRef!;
print("\(identityPointer) :::: \(secIdentityRef)")
// grab the trust
let trustPointer:AnyObject? = certEntry["trust"];
let trustRef:SecTrustRef = trustPointer as! SecTrustRef;
print("\(trustPointer) :::: \(trustRef)")
// grab the cert
let chainPointer:AnyObject? = certEntry["chain"];
identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certArray: chainPointer!);
}
}
return identityAndTrust;
}
Changes done in the info.plist file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>amazonaws.com.cn</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
</dict>
<key>amazonaws.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
</dict>
<key>xyz.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
<key>NSRequiresCertificateTransparency</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
</dict>
</plist>

For someone who interested, this is the small modification from the code of #Karlos, which is compatible with Swift 3.0:
fileprivate func extractCredential(_ certData: Data) -> Credential? {
// REF.: itx | EB418667-6ECD-4D22-B31E-0BB4000849A2
var credential: Credential!
let key = kSecImportExportPassphrase as NSString
let importPasswordOption:NSDictionary = [key as NSString:cerPassword]
var items: CFArray?
let securityError = SecPKCS12Import(certData as CFData, importPasswordOption, &items)
if securityError == errSecSuccess {
let certItems = items as CFArray!
let certItemsArray = (certItems as! NSArray)
let dict = certItemsArray.first
guard let certEntry = certItemsArray.firstObject as? [String:AnyObject] else { fatalError() }
// Identity
let identityPointer = certEntry["identity"];
let secIdentityRef = identityPointer as! SecIdentity!;
// Trust
let trustPointer = certEntry["trust"];
let trustRef = trustPointer as! SecTrust;
// Certificates
let chainPointer = certEntry["chain"];
credential = Credential(identityRef: secIdentityRef!, trust: trustRef, certArray: chainPointer!);
}
return credential;
}

Related

Playing WAV data with AVAudioEngine

Currently, I'm getting an EXC_BAD_ACCESS error on the audio thread, and I'm trying to deduce what is going wrong.
When converting .wav file data from Data to an AVAudioPCMBuffer, do I need to strip the RIFF header first?
import AVFoundation
public class Player : NSObject {
let engine = AVAudioEngine()
public override init() {
super.init()
do {
let _ = engine.mainMixerNode
try engine.start()
} catch {
print("Player error: \(error)")
}
}
#objc public func play(_ data: Data) {
let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 48000, channels: 2, interleaved: true)!
let buffer = data.toPCMBuffer(format: format)!
let player = AVAudioPlayerNode()
engine.attach(player)
engine.connect(player, to: engine.mainMixerNode, format: nil)
player.scheduleBuffer(buffer, at: nil, completionCallbackType: .dataPlayedBack) {
callbackType in
// Nothing in here.
}
player.play()
}
}
Here's the toPCMBuffer extension:
// Taken from: https://stackoverflow.com/a/52731480/2228559
extension Data {
func toPCMBuffer(format: AVAudioFormat) -> AVAudioPCMBuffer? {
let streamDesc = format.streamDescription.pointee
let frameCapacity = UInt32(count) / streamDesc.mBytesPerFrame
guard let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: frameCapacity) else { return nil }
buffer.frameLength = buffer.frameCapacity
let audioBuffer = buffer.audioBufferList.pointee.mBuffers
withUnsafeBytes { addr in
audioBuffer.mData?.copyMemory(from: addr, byteCount: Int(audioBuffer.mDataByteSize))
}
return buffer
}
}
Note: I cannot use AVAudioFile because the .wav file data is loaded over-the-wire.
IDK, but my mac crashes if I play interleaved AVAudioPCMBuffers, and garbled audio if they're not float data, so you could convert to non-interleaved float data:
#objc public func play(_ data: Data) {
let sampleRate: Double = 48000
let interleavedFormat = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: sampleRate, channels: 2, interleaved: true)!
let interleavedBuffer = data.toPCMBuffer(format: interleavedFormat)!
let nonInterleavedFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: sampleRate, channels: 2, interleaved: false)!
let nonInterleavedBuffer = AVAudioPCMBuffer(pcmFormat: nonInterleavedFormat, frameCapacity: interleavedBuffer.frameCapacity)!
nonInterleavedBuffer.frameLength = interleavedBuffer.frameLength
let converter = AVAudioConverter(from: interleavedFormat, to: nonInterleavedFormat)!
try! converter.convert(to: nonInterleavedBuffer, from: interleavedBuffer)
let player = AVAudioPlayerNode()
engine.attach(player)
engine.connect(player, to: engine.mainMixerNode, format: nil)
player.scheduleBuffer(nonInterleavedBuffer, at: nil, completionCallbackType: .dataPlayedBack) {
callbackType in
// Nothing in here.
}
player.play()
}
extension Data {
func toPCMBuffer(format: AVAudioFormat) -> AVAudioPCMBuffer? {
assert(format.isInterleaved)
let streamDesc = format.streamDescription.pointee
let frameCapacity = UInt32(count) / streamDesc.mBytesPerFrame
guard let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: frameCapacity) else { return nil }
buffer.frameLength = buffer.frameCapacity
let b = UnsafeMutableBufferPointer(start: buffer.int16ChannelData![0], count: buffer.stride * Int(frameCapacity))
let bytesCopied = self.copyBytes(to: b)
assert(bytesCopied == count)
return buffer
}
}

AVFoundation: Take High Quality Still Image in Video-Session

I am anlysing live-images in a Capture-Session of Type AVMediaTypeVideo. How can I capture a high-quality-still image (not the low-resolution sample buffer), at certain events=
var videoCaptureDevice: AVCaptureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
var device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
var previewLayer: AVCaptureVideoPreviewLayer?
var captureSession = AVCaptureSession()
let cameraOutput = AVCapturePhotoOutput()
//called in view did load
private func setupCamera() {
let input = try? AVCaptureDeviceInput(device: videoCaptureDevice)
captureSession.sessionPreset = AVCaptureSessionPreset640x480
if self.captureSession.canAddInput(input) {
self.captureSession.addInput(input)
}
self.previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
let videoDataOutput = AVCaptureVideoDataOutput()
if self.captureSession.canAddOutput(videoDataOutput){
self.captureSession.addOutput(videoDataOutput)
videoDataOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
}
}
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
// sampleBuffer is analysed
// if result is positive, I would like to take a high quality picture
}
Here's a little snippet that I use in my apps. I hope this will be helpful
private func takePhoto() -> Void
{
if let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo)
{
videoConnection.videoOrientation = AVCaptureVideoOrientation.portrait
stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (sampleBuffer, error) in
guard let buffer = sampleBuffer else
{
return
}
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
let dataProvider = CGDataProvider(data: imageData as! CFData)
let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!,
decode: nil,
shouldInterpolate: true,
intent: CGColorRenderingIntent.defaultIntent)
// The image taked
let image: UIImage = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: UIImageOrientation.right)
// Detenemos la captura de imagenes
self.captureSession!.stopRunning()
})
}
}
If you don't set the sessionPreset property of your captureSession variable, by default his values is AVCapture​Session​Preset​High. The only preset that is higher than this is AVCaptureSessionPresetPhoto

iOS - Realm Query is not working properly

I am using Swift(2.2) Realm Framework as doing with document. Here is my codes.
class SwipedAsset: Object{
dynamic var identifier = ""
dynamic var createdAt = ""
}
// save data
let realm = try! Realm()
let fileName = asset.originalFilename
if fileName != nil {
let swipedAssets = realm.objects(SwipedAsset.self).filter("identifier == '\(fileName!)'")
let assetCount = swipedAssets.count
if assetCount == 0 {
let swipedAsset = SwipedAsset()
if asset.originalFilename != nil {
swipedAsset.identifier = asset.originalFilename!
}
if asset.creationDate != nil {
let year = String(asset.creationDate!.year)[2...3]
let key = "\(asset.creationDate!.monthName) \(year)"
swipedAsset.createdAt = key
}
let realm = try! Realm()
try! realm.write{
realm.add(swipedAsset)
}
}
}
// load data
let realm = try! Realm()
let swipedAssets = realm.objects(SwipedAsset.self).filter("createdAt == '\(key)'")
let lastObject = swipedAssets.last
print(lastObject.identifier)
print(lastObject.createdAt)
Here, values are all "", "" Nothing, But swipedAssets.count = 3 I thought it means realm's query is working properly.
What's wrong with me ? Thanks for any help.
Please do not try to debug with breakpoint.

'String' does not conform to protocol 'CollectionType' Error in Swift 2.0

I just downloaded XCode Beta 7 and received the error "Type 'String' does not conform to protocol 'CollectionType'". This is my first attempt at coding, so I'm not sure how to fix this. Thank you!!!
//the Pasteboard is nil if full access is not granted
let pbWrapped: UIPasteboard? = UIPasteboard.generalPasteboard()
if let pb = pbWrapped {
var type = UIPasteboardTypeListImage[0] as! String
if (count(type) > 0) && (image != nil) {
pb.setData(UIImagePNGRepresentation(image!)!, forPasteboardType: type)
var readDataWrapped: NSData? = pb.dataForPasteboardType(type)
if let readData = readDataWrapped {
var readImage = UIImage(data: readData, scale: 2)
print("\(image) == \(pb.image) == \(readImage)")
}
}
}
Change it to:
type.characters.count
Your code should then read:
//the Pasteboard is nil if full access is not granted
let pbWrapped: UIPasteboard? = UIPasteboard.generalPasteboard()
if let pb = pbWrapped {
var type = UIPasteboardTypeListImage[0] as! String
if (type.characters.count > 0) && (image != nil) {
pb.setData(UIImagePNGRepresentation(image!)!, forPasteboardType: type)
var readDataWrapped: NSData? = pb.dataForPasteboardType(type)
if let readData = readDataWrapped {
var readImage = UIImage(data: readData, scale: 2)
print("\(image) == \(pb.image) == \(readImage)")
}
}
}
Just a suggestion for where to start learning about this issue... https://developer.apple.com/swift/blog/?id=30
Strings in Swift 2

Issue decrypting with CommonCrypto in Swift

I am working in a Swift-only crypt/decrypt Extension for String and NSData, and the crypt part is working based in the answer provided by #Zaph in the linked question: Issue using CCCrypt (CommonCrypt) in Swift
The crypt output was tested using the good old NSData+AESCrypt.m Category in Objective-C
I have been working in the decrypt part with an issue: The code compiles and runs fine, but the result is not the expected text originally encrypted.
extension NSData {
func AES256EncryptDataWithKey(key: String) -> NSData {
let keyData: NSData! = (key as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let keyBytes = UnsafePointer<UInt8>(keyData.bytes)
let keyLength = size_t(kCCKeySizeAES256)
let dataLength = UInt(self.length)
let dataBytes = UnsafePointer<UInt8>(self.bytes)
let bufferData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
var bufferPointer = UnsafeMutablePointer<UInt8>(bufferData.mutableBytes)
let bufferLength = size_t(bufferData.length)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
var numBytesEncrypted: UInt = 0
var cryptStatus = CCCrypt(operation,
algoritm,
options,
keyBytes, keyLength,
nil,
dataBytes, dataLength,
bufferPointer, bufferLength,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
bufferData.length = Int(numBytesEncrypted) // Requiered to adjust buffer size
return bufferData as NSData
} else {
println("Error: \(cryptStatus)")
return NSData()
}
}
func AES256DecryptDataWithKey(key: String) -> NSData {
let keyData: NSData! = (key as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let keyBytes = UnsafePointer<UInt8>(keyData.bytes)
let keyLength = size_t(kCCKeySizeAES256)
let dataLength = UInt(self.length)
let dataBytes = UnsafePointer<UInt8>(self.bytes)
let string = self.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
let bufferData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
var bufferPointer = UnsafeMutablePointer<UInt8>(bufferData.mutableBytes)
let bufferLength = size_t(bufferData.length)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
var numBytesDecrypted: UInt = 0
var cryptStatus = CCCrypt(operation,
algoritm,
options,
keyBytes, keyLength,
nil,
dataBytes, dataLength,
bufferPointer, bufferLength,
&numBytesDecrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
bufferData.length = Int(numBytesDecrypted) // Requiered to adjust buffer size
return bufferData as NSData
} else {
println("Error: \(cryptStatus)")
return NSData()
}
}
}
extension String {
func AES256EncryptStringWithKey(key: String) -> String {
let data = (self as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let encryptedData = data.AES256EncryptDataWithKey(key)
// Not all data is a UTF-8 string so Base64 is used
let base64cryptString = encryptedData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
return base64cryptString
}
func AES256DecryptStringWithKey(key: String) -> String {
let data: NSData! = (self as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let decryptedData = data.AES256DecryptDataWithKey(key)
// Not all data is a UTF-8 string so Base64 is used
let base64decryptString = decryptedData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
return base64decryptString
}
}
As you can see the String.encryptStringWithKey() calls the NSData.encryptDataWithKey(). so the Extensions work for both types String and NSData
let string: String = "Don´t try to read this text. Top Secret Stuff"
let key = "12345678901234567890123456789012"
println("Original String : \(string)");
let encryptedString = string.AES256EncryptStringWithKey(key)
println("Encrypted String : \(encryptedString)")
let decryptedString = encryptedString.AES256DecryptStringWithKey(key)
println("Decrypted String: \(decryptedString)")
Any help will be appreciated
The difference is that NSData+AESCrypt.m is using CBC mode (the default) with an iv of NULL. The code in the question is using ECB mode.
Best practice is to use CBC mode with a random iv. The iv is typically pre-pended to the encrypted data so the decryption can separate the iv and data prior to decryption.
Do not use NSData+AESCrypt.m, it has not been maintained, is a category on NSData, does not support ARC. Consider RNCryptor for Objective-C, it is actively maintained.
This is the change I made in "NSData+AESCrypt.m", method AES256EncryptWithKey: kCCOptionPKCS7Padding + kCCOptionECBMode. I added kCCOptionECBMode, that's all.
Here is the call I made:
NSString *keyString = #"12345678901234567890123456789012";
NSString *message = #"Don´t try to read this text. Top Secret Stuff";
NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
NSData *crypData = [data AES256EncryptWithKey:keyString];
NSLog(#"crypData: %#", crypData);
Output:
crypData: <118a32dc c23f7caa 883abc3c 1c7f0770 e200016b 2737acfa 17bb96fb a02b02a7 c147603b 06acd863 94bb8ff2 6cb14515>
Which is the same as from the above code (the same as the previous question):
cryptData = <118a32dc c23f7caa 883abc3c 1c7f0770 e200016b 2737acfa 17bb96fb a02b02a7 c147603b 06acd863 94bb8ff2 6cb14515>
It is just a matter of getting all of the inputs the same: operation, algorithm, options, keyBytes, keyLength, dataBytes, dataLength and iv if non ECB mode. CCCrypt is just a function call, that's all. Put in the same input, get the same output.
Put in NSLog() statements, preferably hex dumps for data and strings. Compare and fix as needed.
Believe it or not, this is the easy part of electronic security.
Swift 2.0 AES128 Encryption and Decryption.
Should import the following header into Obj-c bridge header inorder to work
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonKeyDerivation.h>
static func AES128Encryption()
{
let keyString = "12345678901234567890123456789012"
let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let keyBytes = UnsafeMutablePointer<Void>(keyData.bytes)
print("keyLength = \(keyData.length), keyData = \(keyData)")
let message = "Don´t try to read this text. Top Secret Stuff"
let data: NSData! = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let dataLength = size_t(data.length)
let dataBytes = UnsafeMutablePointer<Void>(data.bytes)
print("dataLength = \(dataLength), data = \(data)")
let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes)
let cryptLength = size_t(cryptData!.length)
let keyLength = size_t(kCCKeySizeAES256)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding + kCCOptionECBMode)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
keyBytes, keyLength,
nil,
dataBytes, dataLength,
cryptPointer, cryptLength,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
// let x: UInt = numBytesEncrypted
cryptData!.length = Int(numBytesEncrypted)
print("cryptLength = \(numBytesEncrypted), cryptData = \(cryptData)")
// Not all data is a UTF-8 string so Base64 is used
let base64cryptString = cryptData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
print("base64cryptString = \(base64cryptString)")
} else {
print("Error: \(cryptStatus)")
}
}
static func AES128Decryption(data:NSData) //data = cryptData
{
let keyString = "12345678901234567890123456789012"
let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let keyBytes = UnsafeMutablePointer<Void>(keyData.bytes)
print("keyLength = \(keyData.length), keyData = \(keyData)")
//let message = "Don´t try to read this text. Top Secret Stuff"
// let data: NSData! = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let dataLength = size_t(data.length)
let dataBytes = UnsafeMutablePointer<Void>(data.bytes)
print("dataLength = \(dataLength), data = \(data)")
let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes)
let cryptLength = size_t(cryptData!.length)
let keyLength = size_t(kCCKeySizeAES256)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding + kCCOptionECBMode)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
keyBytes, keyLength,
nil,
dataBytes, dataLength,
cryptPointer, cryptLength,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
// let x: UInt = numBytesEncrypted
cryptData!.length = Int(numBytesEncrypted)
print("DecryptcryptLength = \(numBytesEncrypted), Decrypt = \(cryptData)")
// Not all data is a UTF-8 string so Base64 is used
let base64cryptString = cryptData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
print("base64DecryptString = \(base64cryptString)")
print( "utf8 actual string = \(NSString(data: cryptData!, encoding: NSUTF8StringEncoding))");
} else {
print("Error: \(cryptStatus)")
}
}
Swift4 AES128 Decryption and JWT
Note: If iv is used along with key while encrypting the plain text dont use it while decrypting , your issue will be resolved.
key and iv length is 16bit
Following code for decryption may help you:
Here the encrypted string used for decryption is base64Encoded and the decrypted string which we get is JWT(Json Web Token).
To Configure CommonCrypto refer link:
How is CommonCrypto used in SWIFT3?
https://www.devglan.com/online-tools/aes-encryption-decryption
https://jwt.io/
import UIKit
import CommonCrypto
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
testAES()
}
func testAES() {
let testMessSr = "74oIlwieBbxGvHjibQoSxWWAL0zNfy7yaQboYizPc+ouMsAkXbvMNb0RagXklA2zOlo29J7Zr7zFiOalBfKSvV3pzw7KWCtTMw16SNeOIRWYpSWNcNXxgoQR7Jy33s0JP8elQCo/6G+inivE2hm3kl7QTr/Jz5bx/ho0LmWrirn/L4WAJlDFHue23vjhrKGIfEvwIdWHPNh1qd+hCY4pQA==:NjkzQUU1MkM5RTZERjNFMA=="
//Here I'm separating iv from base64encoded string as while decrypting theres no need of iv
let splitStr = testMessSr.components(separatedBy: ":")
print("base64EncodedString: \(splitStr[0])")
print("iv: \(splitStr[1])")
let base64EncodedString = splitStr[0]
let message = Data(base64Encoded: base64EncodedString ,options : Data.Base64DecodingOptions.ignoreUnknownCharacters)
let key = "EE99C7A159003D36"
let ivString = "693AE52C9E6DF3E0" // 16 bytes for AES128
// let messageData = message.data(using:String.Encoding.utf8)!
let keyData = key.data(using: .utf8)!
let ivData = ivString.data(using: .utf8)!
let decryptedData = message?.aesEncrypt( keyData:keyData, ivData:ivData, operation:kCCDecrypt)
print("decryptedData: \(decryptedData)")
let decryptedString = String(data: decryptedData as! Data, encoding: String.Encoding.utf8)
print("decryptedString: \(decryptedString)") //JWT token
}
}
extension Data{
func aesEncrypt( keyData: Data, ivData: Data, operation: Int) -> Data {
let dataLength = self.count
let cryptLength = size_t(dataLength + kCCBlockSizeAES128)
var cryptData = Data(count:cryptLength)
let keyLength = size_t(kCCKeySizeAES128)
let options = CCOptions(kCCOptionPKCS7Padding)
var numBytesEncrypted :size_t = 0
let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
self.withUnsafeBytes {dataBytes in
ivData.withUnsafeBytes {ivBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(operation),
CCAlgorithm(kCCAlgorithmAES),
options,
keyBytes, keyLength,
ivBytes,
dataBytes, dataLength,
cryptBytes, cryptLength,
&numBytesEncrypted)
}
}
}
}
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.removeSubrange(numBytesEncrypted..<cryptData.count)
} else {
print("Error: \(cryptStatus)")
}
return cryptData;
}
}