Code Monkey home page Code Monkey logo

Comments (6)

hfossli avatar hfossli commented on July 17, 2024

Hi! Thanks for letting me know about this use case!

It was slightly tricky. 2 things where off.

  1. The signature that Security/EllipticCurveKeyPair produces is in DER format. The API expects a raw signature of 64 bytes for ES256.
  2. The API expects a base64 uri safe variant

I managed to produce a valid JWToken

eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJ0ZXN0dXNlcm5hbWUiLCJzdWIiOiJ0ZXN0Y2xpZW50aWQiLCJpYXQiOjE1MDE1MDk3ODIsImV4cCI6MTUwMTUwOTg0Mn0.9bUeggjl9sOdfxqOOcMv7uE6MUBrhEMWEFDLI1xiD4HwO8oSK_TuveST4imEug13h7hthgy1uwYPa0Fb7M4N3w

-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXum2ZYo0Qp2foJRIKPP2eGNT82y6
GgZgRGKWB8DArDhKQAhjp/RQFCoP8Olq4QtL5l4jcdKZhvOTAd47r7tAvQ==
-----END PUBLIC KEY-----

Here's the code

import EllipticCurveKeyPair

extension Data {
    func base64EncodedStringURISafe() -> String {
        return self.base64EncodedString()
            .replacingOccurrences(of: "+", with: "-")
            .replacingOccurrences(of: "/", with: "_")
            .replacingOccurrences(of: "=", with: "")
    }
}

func DEREC256SignatureDecode(_ signature: Data) -> Data {
    // example https://lapo.it/asn1js/#3046022100F309E36DFA5FE0BFBF5C3855E06E9C3C7D04DE347E2B345C3392DDB98E13BE6302210080372B3BBAE5E370B976092B8AA64F4EF1025FFE893D0046FA085F256AE04761
    var decoded = signature
    let maxChunkSize = 32
    decoded.removeFirst() // removing sequence header
    decoded.removeFirst() // removing sequence size
    decoded.removeFirst() // removing 'r' element header
    let rLength = Int(decoded.removeFirst()) // removing 'r' element length
    let r  = decoded.prefix(rLength).suffix(maxChunkSize) // read out 'r' bytes and discard any padding
    decoded.removeFirst(Int(rLength)) // removing 'r' bytes
    decoded.removeFirst() // 's' element header
    let sLength = Int(decoded.removeFirst()) // 's' element length
    let s  = decoded.prefix(sLength).suffix(maxChunkSize) // read out 's' bytes and discard any padding
    return Data(r) + Data(s)
}

let keysManager: EllipticCurveKeyPair.Manager = {
    let publicAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAlwaysThisDeviceOnly, flags: [])
    let privateAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, flags: [.privateKeyUsage, .userPresence])
    let config = EllipticCurveKeyPair.Config(
        publicLabel: "test.sign.public",
        privateLabel: "test.sign.private",
        operationPrompt: "Json web token",
        publicKeyAccessControl: publicAccessControl,
        privateKeyAccessControl: privateAccessControl,
        token: .secureEnclave)
    return EllipticCurveKeyPair.Manager(config: config)
}()

func testJWT() {
    do {
        try? keysManager.deleteKeyPair()
        
        let headerAndPayload = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJ0ZXN0dXNlcm5hbWUiLCJzdWIiOiJ0ZXN0Y2xpZW50aWQiLCJpYXQiOjE1MDE1MDk3ODIsImV4cCI6MTUwMTUwOTg0Mn0"
        let derSignature = try keysManager.sign(headerAndPayload.data(using: .utf8)!, hash: .sha256)
        let decodedSignature = DEREC256SignatureDecode(derSignature)
        let token = headerAndPayload + "." + decodedSignature.base64EncodedStringURISafe()
        
        print("headerAndPayloadAsString: \(headerAndPayload)")
        print("signature: \(derSignature.base64EncodedStringURISafe())")
        print("decoded signature: \(decodedSignature.base64EncodedStringURISafe())")
        print("token: \(token)")
        print("public key: \n\(try keysManager.publicKey().data().PEM)")
        
        try keysManager.verify(signature: derSignature,
                               originalDigest: headerAndPayload.data(using: .utf8)!,
                               hash: .sha256)
        print("valid!")
    } catch {
        print("error: \(error)")
    }
}

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // Insert code here to initialize your application
        
        testJWT()
    }

from ellipticcurvekeypair.

hfossli avatar hfossli commented on July 17, 2024

There's some mutual interests here yourkarma/JWT#116

from ellipticcurvekeypair.

smamczak avatar smamczak commented on July 17, 2024

Hi, everything works! I'm really grateful for the speed of response and example!

from ellipticcurvekeypair.

hfossli avatar hfossli commented on July 17, 2024

Great! I'm keeping this open until I have this included somehow

from ellipticcurvekeypair.

smamczak avatar smamczak commented on July 17, 2024

That would be nice too. The sign method could have a param like so

enum SignatureFormat {
    case der
    case raw
}
public func sign(_ digest: Data, hash: Hash, format: SignatureFormat = .der, context: LAContext? = nil) throws -> Data {
}

but this is just a suggestion

from ellipticcurvekeypair.

hfossli avatar hfossli commented on July 17, 2024

👍👍 Yep, either that or return an object with two variables.

from ellipticcurvekeypair.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.