Digitale handtekeningen maken met Swift

Het belangrijkste doel van een digitale handtekening is om de integriteit van bepaalde informatie te verifiëren. Laten we voor een eenvoudig voorbeeld zeggen dat u een bestand had dat over het netwerk was verzonden en u wilt controleren of het volledige bestand correct is overgebracht. In dat geval zou u een controlesom gebruiken.

"Een controlesom is een klein gegeven dat afkomstig is van een blok digitale gegevens om fouten te detecteren die mogelijk zijn geïntroduceerd tijdens de overdracht of opslag" - Wikipedia

Hoe leiden we die controlesom af? De beste optie is om een ​​hash te gebruiken. Een hash-functie neemt een variabele hoeveelheid gegevens in beslag en geeft een handtekening met een vaste lengte weer. We kunnen bijvoorbeeld een bestand samen met zijn hash online publiceren. Wanneer iemand het bestand downloadt, kunnen ze dezelfde hashfunctie uitvoeren op hun versie van het bestand en het resultaat vergelijken. Als de hashes hetzelfde zijn, is het gekopieerde of gedownloade bestand hetzelfde als het origineel. 

Een hash is ook een eenrichtingsfunctie. Gezien de resulterende output is er geen computationeel haalbare manier om die hasj om te keren om te onthullen wat de oorspronkelijke invoer was. SHA, Secure Hash Algorithm, is een bekende standaard die verwijst naar een groep hashfuncties die deze eigenschap en bepaalde andere hebben, waardoor ze nuttig zijn voor digitale handtekeningen.

Over SHA

SHA heeft vele iteraties ondergaan sinds het voor het eerst werd gepubliceerd. Van de eerste en tweede iteraties, SHA-0 en SHA-1, staat nu bekend dat ze grote zwakke punten hebben. Ze zijn niet langer goedgekeurd voor beveiligingsimplementaties: ze mogen over het algemeen niet worden gebruikt voor toepassingen die op beveiliging vertrouwen. De SHA-2-familie omvat echter versies genaamd SHA-256 en SHA-512 en deze worden als veilig beschouwd. "256" en "512" verwijzen eenvoudigweg naar het resulterende aantal geproduceerde bits. Voor deze tutorial gaan we SHA-512 gebruiken.

Opmerking: een ander ouder populair hash-algoritme was MD5. Het bleek ook significante gebreken te hebben.

Het gebruik van SHA is geweldig om te controleren of gegevens per ongeluk zijn beschadigd, maar dit belet niet dat een kwaadwillende gebruiker met de gegevens knoeit. Aangezien een hash-output een vaste grootte heeft, hoeft een aanvaller alleen maar uit te zoeken welk algoritme werd gebruikt, gegeven de uitvoergrootte, de gegevens te wijzigen en de hash opnieuw te berekenen. Wat we nodig hebben, is geheime informatie die aan de mix wordt toegevoegd wanneer de gegevens worden hashing, zodat de aanvaller de hash niet opnieuw kan berekenen zonder kennis van het geheim. Dit wordt een Hash Message Authentication Code (HMAC) genoemd.

HMAC

HMAC kan een stuk informatie of een bericht verifiëren om te controleren of het afkomstig is van de juiste afzender en dat de informatie niet is gewijzigd. Een veelvoorkomend scenario is wanneer u praat met een server met een backend-API voor uw app. Het kan belangrijk zijn om te verifiëren om ervoor te zorgen dat alleen uw app met de API mag praten. De API zou hebben toegangscontrole naar een specifieke bron, zoals een / register_user eindpunt. De klant zou dit moeten doen teken zijn verzoek aan de / register_user eindpunt om het met succes te kunnen gebruiken.

Bij het ondertekenen van een aanvraag is het gebruikelijk om geselecteerde delen van het verzoek, zoals POST-parameters en de URL, te nemen en ze samen te voegen tot een tekenreeks. Het afspreken van afgesproken elementen en het in een bepaalde volgorde plaatsen ervan wordt genoemd standaardisatieproblemen. In HMAC wordt de gekoppelde tekenreeks samen met de geheime sleutel gehashed om de handtekening. In plaats van het een hash te noemen, gebruiken we de term handtekening op dezelfde manier als de handtekening van een persoon in het echte leven wordt gebruikt om identiteit of integriteit te verifiëren. De handtekening wordt als verzoekkop toegevoegd aan het verzoek van de klant (meestal ook "Handtekening" genoemd). Een handtekening wordt soms een berichtoverzicht genoemd, maar de twee termen kunnen door elkaar worden gebruikt.

Aan de kant van de API herhaalt de server het proces om lid te worden van de strings en een handtekening te maken. Als de handtekeningen overeenkomen, bewijst het dat de app het geheim in bezit moet hebben. Dit bewijst de identiteit van de app. Omdat specifieke parameters van het verzoek ook deel uitmaakten van de te ondertekenen reeks, garandeert dit ook de integriteit van het verzoek. Het voorkomt bijvoorbeeld dat een aanvaller een man-in-the-middle-aanval uitvoert en de verzoekparameters naar wens aanpast.

class func hmacExample () // Voorbeeld van een bepaalde URL ... laat urlString = "https://example.com" postString = "id = 123" laten url = URL.init (string: urlString) var request = URLRequest (url: url!) request.httpMethod = "POST" request.httpBody = postString.data (using: .utf8) let session = URLSession.shared // Maak een handtekening laat stringToSign = request.httpMethod! + "&" + urlString + "&" + postString print ("De te ondertekenen string is:", stringToSign) als dataToSign = stringToSign.data (met: .utf8) let signingSecret = "4kDfjgQhcw4dG6J80QnvRFbtuJfkgitH6phkLN90" als signingSecretData = signingSecret .data (met: .utf8) let digestLength = Int (CC_SHA512_DIGEST_LENGTH) laat digestBytes = UnsafeMutablePointer.allocate (capacity: digestLength) CCHmac (CCHmacAlgorithm (kCCHmacAlgSHA512), [UInt8] (signingSecretData), signingSecretData.count, [UInt8] (dataToSign), dataToSign.count, digestBytes) // base64 output laat hmacData = Data (bytes: digestBytes, count: digestLength) let signature = hmacData.base64EncodedString () print ("De HMAC-handtekening in base64 is" + handtekening) // of HEX-uitvoer laat hexString = NSMutableString () voor i in 0 ...  

In deze code, de CCHmac functie neemt een parameter voor het type hash-functie dat moet worden gebruikt, samen met twee byte-strings en hun lengtes: het bericht en een geheime sleutel. Gebruik voor de beste beveiliging ten minste een 256-bits (32 byte) sleutel die is gegenereerd op basis van een cryptografisch beveiligde willekeurige nummergenerator. Om te controleren of alles goed werkt aan de andere kant, voert u het voorbeeld uit en voert u vervolgens de geheime sleutel en het bericht op deze externe server in en controleert u of de uitvoer hetzelfde is.

U kunt ook een tijdstempelkop toevoegen aan de tekenverzoek- en ondertekenreeks om de aanvraag unieker te maken. Dit kan de API-wiet helpen om aanvallen opnieuw uit te voeren. De API kan het verzoek bijvoorbeeld laten vervallen als het tijdstempel 10 minuten oud is.

Hoewel het goed is om vast te houden aan het gebruik van SHA-versies die veilig zijn, blijken veel van de kwetsbaarheden van de onveilige SHA-versies niet van toepassing op HMAC. Om deze reden ziet u mogelijk SHA1 worden gebruikt in de productiecode. Vanuit een public relations-standpunt kan het echter slecht lijken als je moet uitleggen waarom, in cryptografisch opzicht, het OK is om SHA1 in deze context te gebruiken. Veel van de zwakke punten van SHA1 zijn te wijten aan wat er wordt genoemd botsing aanvallen. Code auditors of beveiligingsonderzoekers mogen verwachten dat uw code bestand is tegen botsingen, ongeacht de context. Als u modulaire code schrijft, waarbij u de ondertekeningsfunctie in de toekomst kunt omwisselen voor een andere, zou u kunnen vergeten de onveilige hash-functies bij te werken. Daarom zullen we ons nog steeds houden aan SHA-512 als ons gekozen algoritme.

De HMAC CPU-bewerkingen zijn snel, maar een nadeel is het probleem van sleuteluitwisseling. Hoe laten we elkaar weten wat de geheime sleutel is zonder dat deze wordt onderschept? Misschien moet uw API bijvoorbeeld dynamisch meerdere apps of platforms van een witte lijst toevoegen of verwijderen. In dit scenario moeten apps zich registreren en moet het geheim na succesvolle registratie aan de app worden doorgegeven. U kunt de sleutel over HTTPS verzenden en SSL-pinning gebruiken, maar zelfs dan is er altijd een zorg dat de sleutel op de een of andere manier tijdens de uitwisseling wordt gestolen. De oplossing voor het probleem van sleuteluitwisseling is om een ​​sleutel te genereren die het apparaat nooit hoeft te verlaten. Dit kan worden bereikt met Public Key Cryptography en een zeer populaire en geaccepteerde standaard is RSA.

RSA

RSA staat voor Rivest-Shamir-Adleman (de auteurs van het cryptosysteem). Het gaat om het benutten van de moeilijkheidsgraad van het factoring van het product van twee zeer grote priemgetallen. RSA kan worden gebruikt voor codering of authenticatie, hoewel we dit voorbeeld voor authenticatie zullen gebruiken. RSA genereert twee sleutels, een publieke en een private, die we kunnen bereiken met behulp van de SecKeyGeneratePair functie. Bij gebruik voor verificatie wordt de privésleutel gebruikt om de handtekening te maken, terwijl de openbare sleutel de handtekening verifieert. Met een publieke sleutel is het rekenkundig niet haalbaar om de private sleutel af te leiden.

Het volgende voorbeeld laat zien wat Apple en alle populaire spelcomputerbedrijven gebruiken bij het distribueren van hun software. Stel dat uw bedrijf periodiek een bestand maakt en aflevert dat gebruikers in iTunes naar het gedeelte voor het delen van bestanden van uw app zullen slepen. U wilt er zeker van zijn dat de bestanden die u verzendt nooit worden gemanipuleerd voordat ze in de app worden geparseerd. Uw bedrijf bewaart en bewaakt de privésleutel die wordt gebruikt om de bestanden te ondertekenen. In de bundel van de app staat een kopie van de openbare sleutel die wordt gebruikt om het bestand te verifiëren. Aangezien de privésleutel nooit wordt overgedragen of wordt opgenomen in de app, kan een kwaadwillende gebruiker geen manier zien om zijn eigen versies van de bestanden te ondertekenen (behalve inbraak in het bedrijf en het stelen van de privésleutel).

We zullen gebruiken SecKeyRawSign om het bestand te ondertekenen. Het zou traag zijn om de volledige inhoud van het bestand met RSA te ondertekenen, dus de hash van het bestand wordt in plaats daarvan ondertekend. Bovendien moeten de gegevens die aan RSA worden doorgegeven ook worden gehasht voordat ze worden ondertekend vanwege een aantal zwakke punten in de beveiliging.

@available (iOS 10.0, *) class FileSigner private var publicKey: SecKey? privé var privateKey: SecKey? func generateKeys () -> String? var publicKeyString: String? // genereer een nieuw keypair laat de parameters: [String: AnyObject] = [kSecAttrKeyType als String: kSecAttrKeyTypeRSA, kSecAttrKeySizeInBits as String: 4096 as AnyObject,] let status = SecKeyGeneratePair (parameters als CFDictionary, & publickey & privateKey) // --- Save jouw sleutel hier --- // // Converteer het SecKey-object naar een representatie die we kunnen verzenden via het netwerk als status == noErr && publicKey! = nil if let cfData = SecKeyCopyExternalRepresentation (publicKey !, nil) let data = cfData als Data publicKeyString = data.base64EncodedString () return publicKeyString func signFile (_ path: String) -> String? var signature: String? if let fileData = FileManager.default.contents (atPath: path) if (privateKey! = nil) // hash het bericht laat eerst digestLength = Int (CC_SHA512_DIGEST_LENGTH) let hashBytes = UnsafeMutablePointer.allocate (capacity: digestLength) CC_SHA512 ([UInt8] (bestandsdata), CC_LONG (fileData.count), hashBytes) // sign let blockSize = SecKeyGetBlockSize (privateKey!) // in het geval van RSA is de modulus gelijk aan het blok size var signatureBytes = [UInt8] (herhalende: 0, count: blockSize) var signatureDataLength = blockSize let status = SecKeyRawSign (privateKey !, .PKCS1SHA512, hashBytes, digestLength, & signatureBytes, & signatureDataLength) if status == noErr let data = Data ( bytes: signatureBytes, count: signatureDataLength) signature = data.base64EncodedString () return signature

In deze code gebruikten we de CC_SHA512 functie om SHA-512 opnieuw op te geven. (RSA wordt, in tegenstelling tot HMAC, onveilig als de onderliggende hashfunctie onveilig is.) We gebruiken ook 4096 als de sleutelgrootte, die wordt ingesteld door de kSecAttrKeySizeInBits parameter. 2048 is de aanbevolen minimumgrootte. Dit is om te voorkomen dat een krachtig netwerk van computersystemen de RSA-sleutel kraakt (door te kraken bedoel ik het factoring van de RSA-sleutel, ook wel factorisatie van een openbare modulus genoemd). De RSA-groep heeft geschat dat 2048-bits sleutels ergens vóór 2030 kunnen worden gekraakt. Als u wilt dat uw gegevens na die tijd veilig zijn, is het een goed idee om een ​​hogere sleutelgrootte te kiezen, zoals 4096.

De gegenereerde sleutels hebben de vorm van SecKey voorwerpen. Een probleem met de implementatie door Apple van SecKey is dat het niet alle essentiële informatie bevat waaruit een openbare sleutel bestaat, dus het is geen geldig DER-gecodeerd X.509-certificaat. Het toevoegen van de ontbrekende informatie in de indeling voor een iOS- of OS X-app, zelfs server-side platforms zoals PHP, vereist wat werk en houdt in dat je werkt in een formaat dat bekend staat als ASN.1. Gelukkig is dit opgelost in iOS 10 met nieuw SecKey functies voor het genereren, exporteren en importeren van sleutels. 

De onderstaande code toont u de andere kant van de communicatie: de klasse die een openbare sleutel accepteert via SecKeyCreateWithData om bestanden te verifiëren met behulp van de SecKeyRawVerify functie.

@available (iOS 10.0, *) class FileVerifier private var publicKey: SecKey? func addPublicKey (_ keyString: String) -> Bool var succes = false als keyData = Data.init (base64Encoded: keyString) let parameters: [String: AnyObject] = [kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPublic , kSecAttrKeySizeInBits als tekenreeks: 4096 as AnyObject, kSecReturnPersistentRef as String: true als AnyObject] publicKey = SecKeyCreateWithData (keyData als CFData, parameters als CFDictionary, nil) if (publicKey! = nil) success = true return success func verifyFile ( _ path: String, withSignature signature: String) -> Bool var successful = false if (publicKey! = nil) if letData = FileManager.default.contents (atPath: pad) if letDataData = Data.init (base64Encoded : handtekening) // hash het bericht liet eerst digestLength = Int (CC_SHA512_DIGEST_LENGTH) laat hashBytes = UnsafeMutablePointer.toewijzen (capaciteit: digestLength) CC_SHA512 ([UInt8] (bestandsgegevens), CC_LONG (bestandsgegevens.count), hashBytes) // verifieer laat status = signatureData.withUnsafeBytes signatureBytes in ruil SecKeyRawVerify (publicKey !, .PKCS1SHA512, hashBytes, digestLength, signatureBytes , signatureData.count) if status == noErr success = true else print ("Signature verify error") // - 9809: errSSLCrypto, etc return success

U kunt dit uitproberen en controleren of het werkt met een eenvoudige test zoals de volgende:

if #beschikbaar (iOS 10.0, *) bewaker laat plistPath = Bundle.main.path (voorResource: "Info", ofType: "plist") else print ("Could not get plist"); return let fileSigner = FileSigner () DispatchQueue.global (qos: .userInitiated) .async // RSA-sleutelgen kan langlopend werk zijn guard let publicKeyString = fileSigner.generateKeys () else print ("Key generation error"); return // Terug naar de hoofdthread DispatchQueue.main.async guard let signature = fileSigner.signFile (plistPath) else print ("Geen handtekening"); return // Bewaar de handtekening aan de andere kant laat fileVerifier = FileVerifier () guard fileVerifier.addPublicKey (publicKeyString) else print ("Key was not added"); return let success = fileVerifier.verifyFile (plistPath, withSignature: signature) als succes print ("Signatures match!") else print ("Signatures komen niet overeen.") 

Er is één nadeel aan RSA-sleutelgeneratie is traag! De tijd voor het genereren van de toetsen is afhankelijk van de grootte van de sleutel. Op nieuwere apparaten duurt een 4096-bitsleutel slechts enkele seconden, maar als u deze code uitvoert op een iPod Touch 4th Generation, kan dit ongeveer een minuut duren. Dit is prima als u de toetsen een paar keer op een computer genereert, maar wat gebeurt er als we vaak sleutels moeten genereren op een mobiel apparaat? We kunnen niet alleen de toetsgrootte verlagen, want dat verlaagt de beveiliging. 

Dus wat is de oplossing? Welnu, Elliptic Curve Cryptography (ECC) is een opkomende benadering-een nieuwe set algoritmen gebaseerd op elliptische krommen over eindige velden. ECC-sleutels zijn veel kleiner en sneller te genereren dan RSA-sleutels. Een sleutel van slechts 256-bits biedt een zeer sterk beveiligingsniveau! Om te profiteren van ECC hoeven we niet veel code te wijzigen. We kunnen onze gegevens met dezelfde ondertekenen SecKeyRawSign functie en pas dan de parameters aan om Elliptic Curve Digital Signature Algorithm (ECDSA) te gebruiken.

Tip: voor meer ideeën voor implementatie van RSA, kunt u de SwiftyRSA helperbibliotheek, die is gericht op versleuteling en het ondertekenen van berichten.

ECDSA

Denk aan het volgende scenario: een chat-app laat gebruikers privéberichten naar elkaar sturen, maar u wilt zeker weten dat een tegenstander het bericht niet heeft gewijzigd op weg naar de andere gebruiker. Laten we eens kijken hoe u hun communicatie met cryptografie kunt beveiligen. 

Ten eerste genereert elke gebruiker een keypair van openbare en privésleutels op zijn mobiele apparaat. Hun privésleutels worden opgeslagen in het geheugen en verlaten het apparaat nooit terwijl de openbare sleutels naar elkaar worden verzonden. Net als voorheen wordt de privésleutel gebruikt voor het ondertekenen van de gegevens die worden verzonden, terwijl de openbare sleutel wordt gebruikt voor verificatie. Als een aanvaller tijdens het transport een openbare sleutel moet vastleggen, kan alleen de integriteit van het originele bericht van de afzender worden geverifieerd. Een aanvaller kan een bericht niet wijzigen omdat deze niet de persoonlijke sleutel heeft die nodig is om de handtekening te reconstrueren.

Er is nog een andere reden om ECDSA op iOS te gebruiken. We kunnen gebruik maken van het feit dat momenteel elliptische curvetoetsen de enige zijn die kunnen worden opgeslagen in de beveiligde enclave van het apparaat. Alle andere sleutels worden opgeslagen in de sleutelhanger die de items versleutelt naar het standaardopslaggebied van het apparaat. Op apparaten die er één hebben, bevindt de veilige enclave zich los van de processor en wordt sleutelopslag geïmplementeerd in hardware zonder directe softwaretoegang. De beveiligde enclave kan een privésleutel opslaan en ernaar werken om uitvoer te produceren die naar uw app wordt verzonden zonder dat de echte privésleutel ooit wordt blootgesteld door deze in het geheugen te laden!

Ik zal ondersteuning toevoegen voor het maken van de ECDSA private key op de beveiligde enclave door het toevoegen van de kSecAttrTokenIDSecureEnclave optie voor de kSecAttrTokenID parameter. We kunnen dit voorbeeld beginnen met een Gebruiker object dat bij het initialiseren een keypair genereert.

@available (iOS 9.0, *) class User public var publicKey: SecKey? privé var privateKey: SecKey? privé var-ontvanger: Gebruiker? init (withUserID id: String) // if let access = SecAccessControlCreateWithFlags (nil, kSecAttrAccessibleWhenPasscodeSetThisDeviceAlleen, [.privateKeyUsage / *, .userPresence] authenticatie-gebruikersinterface om de persoonlijke sleutel te verkrijgen * /], nihil) // Forceer store alleen als toegangscode of Touch ID-instelling ... if let access = SecAccessControlCreateWithFlags (nil, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, [.privateKeyUsage], nil) // Keep private key on device let privateTagString = "com.example.privateKey." + id laat privateTag = privateTagString.data (met gebruik van: .utf8)! // Sla het op als Data, niet als een tekenreeks laat privateKeyParameters: [String: AnyObject] = [kSecAttrIsPermanent als String: true als AnyObject, kSecAttrAccessControl as String: access as AnyObject, kSecAttrApplicationTag as String: privateTag as AnyObject,] let publicTagString = " com.example.publicKey." + id laat publicTag = publicTagString.data (met gebruik van: .utf8)! // Data, niet String laat publicKeyParameters: [String: AnyObject] = [kSecAttrIsPermanent als String: false als AnyObject, kSecAttrApplicationTag as String: publicTag as AnyObject,] laat keyPairParameters: [String: AnyObject] = [kSecAttrKeySizeInBits as String: 256 as AnyObject , kSecAttrKeyType als String: kSecAttrKeyTypeEC, kSecPrivateKeyAttrs als String: privateKeyParameters als AnyObject, kSecAttrTokenID als String: kSecAttrTokenIDSecureEnclave als AnyObject, // Store in Secure Enclave kSecPublicKeyAttrs als String: publicKeyParameters als AnyObject] laat status = SecKeyGeneratePair (keyPairParameters als CFDictionary & publicKey & privateKey) if status! = noErr print ("Key generation error") // ... 

Vervolgens zullen we een aantal helper- en voorbeeldfuncties maken. Als voorbeeld laat de klasse een gebruiker toe een gesprek te starten en een bericht te verzenden. Natuurlijk, in uw app, zou u dit configureren om uw specifieke netwerkinstellingen op te nemen.

 // ... private func sha512Digest (forData-gegevens: gegevens) -> Gegevens let len ​​= Int (CC_SHA512_DIGEST_LENGTH) laat samenvatting = onveilig af te raden.toewijzen (capaciteit: len) CC_SHA512 ((gegevens als NSData) .bytes, CC_LONG (data.count), digest) retourneren NSData (bytesNoCopy: UnsafeMutableRawPointer (digest), length: len) als Data public func initiateConversation (withUser user: User ) -> Bool var success = false if publicKey! = Nil user.receiveInitialization (self) recipient = user success = true return success public func receiveInitialization (_ user: User) recipient = user public func sendMessage (_ message: String) if let data = message.data (using: .utf8) let signature = self.signData (plainText: data) if signature! = nil self.recipient? .receiveMessage (message, withSignature: signature!)  openbare func receiveMessage (_ message: String, withSignature signature: Data) let signatureMatch = verifySignature (plainText: message.data (using: .utf8) !, signature: signature) if signatureMatch print ("Received message. Signature geverifieerd. Bericht is: ", bericht) else print (" Ontvangen bericht. Signature error. ") // ... 

Vervolgens zullen we de daadwerkelijke ondertekening en verificatie uitvoeren. ECDSA hoeft, in tegenstelling tot RSA, niet te worden gehasht voordat het wordt ondertekend. Als u echter een functie wilt hebben waarbij het algoritme eenvoudig kan worden verwisseld zonder veel wijzigingen aan te brengen, is het prima om de gegevens te hashen voordat u ondertekent.

 // ... func signData (plainText: Data) -> Gegevens? guard privateKey! = nil else print ("Private key not available") return nil let digestToSign = self.sha512Digest (forData: plainText) let signature = UnsafeMutablePointer.allocate (capaciteit: 512) // 512 - overhead var handtekeningLength = 512 let status = SecKeyRawSign (privateKey !, .PKCS1SHA512, [UInt8] (digestToSign), Int (CC_SHA512_DIGEST_LENGTH), handtekening en handtekeningLength) if status! = noErr print ( "Signature fail: \ (status)") return Data.init (bytes: handtekening, aantal: signatureLength) // formaat wijzigen naar werkelijke grootte van handtekening func verifySignature (plainText: Data, handtekening: gegevens) -> Bool bewaker ontvanger? .publickey! = nil else print ("openbare sleutel niet beschikbaar") return false let digestToVerify = self.sha512Digest (forData: plainText) laat signedHashBytesSize = signature.count let status = SecKeyRawVerify (recipient! .publickey !, .PKCS1SHA512, [UInt8] (digestToVerify), Int (CC_SHA512_DIGEST_LENGTH), [UInt8] (handtekening als gegevens), signedHashBytesSize) retourstatus == noErr

Hiermee wordt het bericht geverifieerd, evenals het "identificeren" van een specifieke gebruiker, omdat alleen die gebruiker zijn privésleutel bezit. 

Dit betekent niet dat we de sleutel verbinden met wie de gebruiker in het echte leven is - het probleem van het matchen van een openbare sleutel met een specifieke gebruiker is een ander domein. Hoewel de oplossingen buiten de scope van deze tutorial vallen, kunnen gebruikers met populaire veilige chat-apps zoals Signal en Telegram een ​​vingerafdruk of nummer verifiëren via een secundair communicatiekanaal. Op dezelfde manier biedt Pidgin een vraag en antwoordschema waarbij u een vraag stelt die alleen de gebruiker zou moeten weten. Deze oplossingen openen een hele wereld van discussie over wat de beste aanpak zou moeten zijn.

Onze cryptografische oplossing verifieert echter wel of het bericht alleen kan zijn verzonden door iemand die in het bezit is van een specifieke privésleutel.

Laten we een eenvoudige test van ons voorbeeld uitvoeren:

if #beschikbaar (iOS 9.0, *) let alice = User.init (withUserID: "aaaaaa1") laat bob = User.init (withUserID: "aaaaaa2") let accepted = alice.initiateConversation (withUser: bob) if (accepted ) alice.sendMessage ("Hallo daar") bob.sendMessage ("Testbericht") alice.sendMessage ("Nog een testbericht")

OAuth en SSO

Wanneer u met services van derden werkt, ziet u vaak andere termen op hoog niveau die worden gebruikt voor verificatie, zoals OAuth en SSO. Hoewel deze zelfstudie gaat over het maken van een handtekening, zal ik in het kort uitleggen wat de andere termen betekenen.

OAuth is een protocol voor authenticatie en autorisatie. Het fungeert als tussenpersoon om iemands account te gebruiken voor diensten van derden en heeft als doel het probleem op te lossen van het selectief autoriseren van toegang tot uw gegevens. Als u zich aanmeldt bij service X via Facebook, wordt u in een scherm bijvoorbeeld gevraagd of service X toegang heeft tot uw Facebook-foto's. Het doet dit door een token te leveren zonder het wachtwoord van de gebruiker te onthullen.

Single sign-on of SSO beschrijft de stroom waarin een geverifieerde gebruiker dezelfde inloggegevens kan gebruiken om toegang te krijgen tot meerdere services. Een voorbeeld hiervan is hoe uw Gmail-account werkt om u aan te melden bij YouTube. Als u verschillende services in uw bedrijf had, wilt u misschien geen aparte gebruikersaccounts maken voor alle verschillende services.

Conclusie

In deze zelfstudie zag u hoe u handtekeningen kunt maken met behulp van de populairste standaarden. Nu we alle hoofdconcepten hebben behandeld, laten we het samenvatten!

  • Gebruik HMAC wanneer u snelheid nodig hebt en weet zeker dat de geheime sleutel veilig kan worden uitgewisseld.
  • Als de sleutels over een netwerk moeten reizen, is het beter om RSA of ECDSA te gebruiken.
  • RSA is nog steeds de meest populaire standaard. De verificatiestap is vrij snel. Gebruik RSA als de rest van uw team de standaard al kent of gebruikt.
  • Als u echter voortdurend toetsen op een traag apparaat moet genereren, gebruikt u ECDSA. Hoewel de ECDSA-verificatie iets trager is dan RSA-verificatie, is dat niet te vergelijken met de vele seconden die zijn opgeslagen via RSA voor het genereren van sleutels.

Dus dat is het voor digitale handtekeningen in Swift. Als u vragen hebt, kunt u me een bericht sturen in de opmerkingensectie en ondertussen een aantal van onze andere zelfstudies over gegevensbeveiliging en app-ontwikkeling in Swift bekijken.!