From 22688e63e8ce703fa5a888a403b50058afb1792c Mon Sep 17 00:00:00 2001 From: Brian Frank Date: Sun, 21 Apr 2024 17:18:23 -0400 Subject: [PATCH] crypto: few tweaks to Jwt code, add to changelog --- src/crypto/fan/Jwk.fan | 5 +- src/crypto/fan/Jwt.fan | 146 +++++++++++------------ src/cryptoJava/fan/JJwk.fan | 27 +++-- src/cryptoJava/java/JMacKey.java | 5 +- src/cryptoJava/java/JwEcPubKeyPeer.java | 51 ++++---- src/cryptoJava/java/JwRsaPubKeyPeer.java | 13 +- src/doc/docIntro/doc/ChangeLog.fandoc | 1 + 7 files changed, 127 insertions(+), 121 deletions(-) diff --git a/src/crypto/fan/Jwk.fan b/src/crypto/fan/Jwk.fan index e514e38bd..9b0907d4d 100644 --- a/src/crypto/fan/Jwk.fan +++ b/src/crypto/fan/Jwk.fan @@ -3,7 +3,7 @@ // Licensed under the Academic Free License version 3.0 // // History: -// 21 March 2024 Ross Schwalm Creation +// 21 Mar 2024 Ross Schwalm Creation // ** @@ -18,4 +18,5 @@ const mixin Jwk ** Key abstract Key key() -} \ No newline at end of file +} + diff --git a/src/crypto/fan/Jwt.fan b/src/crypto/fan/Jwt.fan index 38e61b882..4b6ffec66 100644 --- a/src/crypto/fan/Jwt.fan +++ b/src/crypto/fan/Jwt.fan @@ -3,7 +3,7 @@ // Licensed under the Academic Free License version 3.0 // // History: -// 21 March 2024 Ross Schwalm Creation +// 21 Mar 2024 Ross Schwalm Creation // ** @@ -22,10 +22,10 @@ ** The (alg) parameter must be set to a supported JWS algorithm. ** ** The following JWS algorithms are supported: -** +** ** - HS256 - HMAC using SHA-256 ** - HS384 - HMAC using SHA-384 -** - HS512 - HMAC using SHA-512 +** - HS512 - HMAC using SHA-512 ** - RS256 - RSASSA-PKCS1-v1_5 using SHA-256 ** - RS384 - RSASSA-PKCS1-v1_5 using SHA-384 ** - RS512 - RSASSA-PKCS1-v1_5 using SHA-512 @@ -42,17 +42,17 @@ const class Jwt ////////////////////////////////////////////////////////////////////////// ** It-block constructor - new make(|This| f) - { + new make(|This| f) + { // call it-block initializer f(this) - + //Initialize Header if (kid == null) this.kid = checkHeaderMap(JwtConst.KeyIdHeader, Str#) //Validate alg Parameter jwsAlg := JwsAlgorithm.fromAlg(alg) this.alg = jwsAlg.toStr - this.header = normalizeHeaderMap + this.header = normalizeHeaderMap //Initialize Registered Claims if (iss == null) this.iss = checkClaimMap(JwtConst.IssuerClaim, Str#) @@ -67,11 +67,11 @@ const class Jwt } private Str:Obj normalizeHeaderMap() - { + { params := [:].addAll(header) if (kid != null) params[JwtConst.KeyIdHeader] = kid params[JwtConst.AlgorithmHeader] = alg - return params + return params } private Str:Obj normalizeClaimsMap() @@ -90,22 +90,22 @@ const class Jwt private Obj? checkHeaderMap(Str parameter, Type type) { if (header[parameter] == null) return null - val := (header[parameter]).typeof == type ? header[parameter] : + val := (header[parameter]).typeof == type ? header[parameter] : throw ArgErr("JWT (${parameter}) header parameter must be ${type.name}") - return val + return val } private Obj? checkClaimMap(Str claim, Type type) { if (claims[claim] == null) return null - val := (claims[claim]).typeof == type ? claims[claim] : + val := (claims[claim]).typeof == type ? claims[claim] : throw ArgErr("JWT (${claim}) claim must be ${type.name}") return val } - ////////////////////////////////////////////////////////////////////////// - // Header - ////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// Header +////////////////////////////////////////////////////////////////////////// ** JOSE Header const Str:Obj header := [:] @@ -119,9 +119,9 @@ const class Jwt ** Algorithm header const Str alg - ////////////////////////////////////////////////////////////////////////// - // Registered Claims - ////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// Registered Claims +////////////////////////////////////////////////////////////////////////// ** JWT Claims const Str:Obj claims := [:] @@ -138,20 +138,20 @@ const class Jwt const Obj? aud ** Expiration claim for this token - ** - ** When encoded, the value will be converted to UTC, the epoch const will be subtracted + ** + ** When encoded, the value will be converted to UTC, the epoch const will be subtracted ** from this value and it will be converted to seconds const DateTime? exp ** Not before claim for this token - ** - ** When encoded, the value will be converted to UTC, the epoch const will be subtracted + ** + ** When encoded, the value will be converted to UTC, the epoch const will be subtracted ** from this value and it will be converted to seconds const DateTime? nbf ** Issued at claim for this token ** - ** When encoded, the value will be converted to UTC, the epoch const will be subtracted + ** When encoded, the value will be converted to UTC, the epoch const will be subtracted ** from this value and it will be converted to seconds const DateTime? iat @@ -193,7 +193,7 @@ const class Jwt ** jwt := Jwt.decode("1111.2222.3333") ** @NoDoc - static new decodeUnsigned(Str encoded) + static new decodeUnsigned(Str encoded) { doDecode(encoded, null) } @@ -229,18 +229,18 @@ const class Jwt verifyExp(claims[JwtConst.ExpirationClaim], clockDrift) verifyNbf(claims[JwtConst.NotBeforeClaim], clockDrift) - if (key is PubKey) - { - if (jwsAlg.keyType != key.algorithm) + if (key is PubKey) + { + if (jwsAlg.keyType != key.algorithm) throw Err("JWT (alg) header parameter \"${jwsAlg.toStr}\" is not compatible with Key algorithm \"${key.algorithm}\"") - if (!((PubKey)key).verify(jwsSigningInput, digestAlgorithm, signature)) + if (!((PubKey)key).verify(jwsSigningInput, digestAlgorithm, signature)) throw Err("Invalid JWT signature") } - else if (key is MacKey) + else if (key is MacKey) { - if(key.algorithm != "Hmac" + jwsAlg.digest) + if(key.algorithm != "Hmac" + jwsAlg.digest) throw Err("JWS (alg) header parameter \"${jwsAlg.toStr}\" is not compatible with Key algorithm \"${key.algorithm}\"") - if(!((MacKey)key).update(jwsSigningInput).digest.bytesEqual(signature)) + if(!((MacKey)key).update(jwsSigningInput).digest.bytesEqual(signature)) throw Err("Invalid JWT MAC") } else @@ -250,7 +250,7 @@ const class Jwt } return Jwt { - it.header = header + it.header = header it.kid = header[JwtConst.KeyIdHeader] it.alg = header[JwtConst.AlgorithmHeader] it.claims = claims @@ -274,14 +274,14 @@ const class Jwt ** ** - HS256 - HMAC using SHA-256 ** - HS384 - HMAC using SHA-384 - ** - HS512 - HMAC using SHA-512 + ** - HS512 - HMAC using SHA-512 ** - RS256 - RSASSA-PKCS1-v1_5 using SHA-256 ** - RS384 - RSASSA-PKCS1-v1_5 using SHA-384 ** - RS512 - RSASSA-PKCS1-v1_5 using SHA-512 ** - ES256 - ECDSA using P-256 and SHA-256 ** - ES384 - ECDSA using P-256 and SHA-384 ** - ES512 - ECDSA using P-256 and SHA-512 - ** - none - No digital signature or MAC performed + ** - none - No digital signature or MAC performed ** ** pair := Crypto.cur.genKeyPair("RSA", 2048) ** priv := pair.priv @@ -293,11 +293,11 @@ const class Jwt ** it.iss = "https://fantom.accounts.dev" ** }.encode(priv) ** - Str encode(Key? key) + Str encode(Key? key) { claimsSet := formatRegisteredClaims - - if (key == null && header[JwtConst.AlgorithmHeader] != "none") + + if (key == null && header[JwtConst.AlgorithmHeader] != "none") throw Err("JWT (${JwtConst.AlgorithmHeader}) header parameter must be \"none\" if key is null") encodedHeader := writeJsonToStr(header).toBuf.toBase64Uri @@ -329,18 +329,18 @@ const class Jwt { claimValue := claims[claim] - if (claimValue is List) + if (claimValue is List) { - if (!((List)claimValue).contains(expectedValue)) - { - throw Err("JWT (${claim}) claim ${claimValue} does not contain expected value: ${expectedValue}") + if (!((List)claimValue).contains(expectedValue)) + { + throw Err("JWT (${claim}) claim ${claimValue} does not contain expected value: ${expectedValue}") } } else { - if (claimValue != expectedValue) - { - throw Err("JWT (${claim}) claim ${claimValue} is not equal to expected value: ${expectedValue}") + if (claimValue != expectedValue) + { + throw Err("JWT (${claim}) claim ${claimValue} is not equal to expected value: ${expectedValue}") } } } @@ -348,9 +348,9 @@ const class Jwt return this } - ////////////////////////////////////////////////////////////////////////// - // Utility Functions - ////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// Utility Functions +////////////////////////////////////////////////////////////////////////// private Str writeJsonToStr(Str:Obj map) { Type.find("util::JsonOutStream").method("writeJsonToStr").call(map) } @@ -389,7 +389,7 @@ const class Jwt { if (aud == null) return null else if (aud is Str) return [(Str)aud] - else if (aud is List) + else if (aud is List) { unique := ((List)aud).unique return unique.findType(Str#) @@ -414,17 +414,17 @@ const class Jwt { signature := "" jwsAlg := JwsAlgorithm.fromAlg(alg) - if (key is PrivKey) + if (key is PrivKey) { - if (jwsAlg.keyType != key.algorithm) - throw Err("JWT (alg) header parameter \"${jwsAlg.toStr}\" is not compatible with Key algorithm \"${key.algorithm}\"") + if (jwsAlg.keyType != key.algorithm) + throw Err("JWT (alg) header parameter \"${jwsAlg.toStr}\" is not compatible with Key algorithm \"${key.algorithm}\"") sigBuf := ((PrivKey)key).sign(signingContent, jwsAlg.digest) if (key.algorithm == "EC") signature = transcodeDerToConcat(sigBuf, 64).toBase64Uri else signature = sigBuf.toBase64Uri } else if (key is MacKey) { - if(key.algorithm != "Hmac" + jwsAlg.digest) + if(key.algorithm != "Hmac" + jwsAlg.digest) throw Err("JWS (alg) header parameter \"${jwsAlg.toStr}\" is not compatible with Key algorithm \"${key.algorithm}\"") sigBuf := ((MacKey)key).update(signingContent).digest signature = sigBuf.toBase64Uri @@ -439,7 +439,7 @@ const class Jwt // The ECDSA signature must be converted to ASN.1 DER bytes for verification // - // JWS ECDSA signatures are formatted as the EC point R and S unsigned integers converted to byte arrays and + // JWS ECDSA signatures are formatted as the EC point R and S unsigned integers converted to byte arrays and // concatenated as defined in [RFC7515]`https://datatracker.ietf.org/doc/html/rfc7515#page-45` private static Buf transcodeConcatToDer(Buf sig) { @@ -450,10 +450,10 @@ const class Jwt j := i if (sig[rawLen - i] < 0) j++ - k := rawLen + k := rawLen while (k > 1 && sig[rawLen*2 - k] == 0) {--k} - l := k + l := k if (sig[rawLen*2 - k] < 0) l++ len := 2 + j + 2 + l @@ -468,7 +468,7 @@ const class Jwt derLen = 2 + 2 + j + 2 + l offset = 1 } - else + else { derLen = 3 + 2 + j + 2 + l setByte = true @@ -555,7 +555,7 @@ const class Jwt ************************************************************************** internal mixin JwtConst -{ +{ // Javascript Object Signing and Encryption (JOSE) Headers const static Str AlgorithmHeader := "alg" const static Str KeyIdHeader := "kid" @@ -581,7 +581,7 @@ enum class JwsAlgorithm hs512, rs256, rs384, - rs512, + rs512, es256, es384, es512, @@ -599,14 +599,14 @@ enum class JwsAlgorithm { alg := params[JwtConst.AlgorithmHeader] if (alg == null) throw Err("Missing (${JwtConst.AlgorithmHeader}) Parameter: ${params}") - algorithm := JwsAlgorithm.vals.find |JwsAlgorithm v->Bool| { return v.name.equalsIgnoreCase(alg) } + algorithm := JwsAlgorithm.vals.find |JwsAlgorithm v->Bool| { return v.name.equalsIgnoreCase(alg) } return algorithm == null ? throw Err("Unsupported or Invalid JWS (alg) Parameter: ${alg}") : algorithm } static new fromKeyAndDigest(Str keyType, Str digest) { - algorithm := JwsAlgorithm.vals.find |JwsAlgorithm v->Bool| - { + algorithm := JwsAlgorithm.vals.find |JwsAlgorithm v->Bool| + { if (keyType != "none") { return v.keyType == keyType && v.digest == digest } else { return v.keyType == keyType } } @@ -627,20 +627,20 @@ enum class JwsAlgorithm public Str keyType() { - firstLetter := name[0..0] - switch(firstLetter) + switch(name[0]) { - case "h": return "oct" - case "r": return "RSA" - case "e": return "EC" - case "n": return "none" + case 'h': return "oct" + case 'r': return "RSA" + case 'e': return "EC" + case 'n': return "none" default: return "none" - } + } } - override Str toStr() - { - if (name != "none") return name.upper - else return name + override Str toStr() + { + if (name != "none") return name.upper + else return name } -} \ No newline at end of file +} + diff --git a/src/cryptoJava/fan/JJwk.fan b/src/cryptoJava/fan/JJwk.fan index 4dfe149cf..0dd243779 100644 --- a/src/cryptoJava/fan/JJwk.fan +++ b/src/cryptoJava/fan/JJwk.fan @@ -3,7 +3,7 @@ // Licensed under the Academic Free License version 3.0 // // History: -// 21 March 2024 Ross Schwalm Creation +// 21 Mar 2024 Ross Schwalm Creation // using web @@ -43,7 +43,7 @@ const class JJwk : Jwk new make(Str:Obj map) { - meta = map + meta = map //Section 6.1 of RFC7518 - JSON Web Algorithms (JWA) if(!meta.containsKey(JwkConst.KeyTypeHeader)) throw Err("JWK missing Key type (${JwkConst.KeyTypeHeader})") @@ -102,7 +102,7 @@ const class JJwk : Jwk if (keysList.size > maxJwKeys) { keysList = keysList.getRange(0..maxJwKeys-1) } jwkList := [,] keysList.each |k| { jwkList = jwkList.add(JJwk(k)) } - return jwkList + return jwkList } ** @@ -112,7 +112,7 @@ const class JJwk : Jwk static Jwk toJwk(Key key, Str digest, Str:Obj meta := [:]) { jwk := [:].addAll(meta) - + if (key is PubKey) { pubKey := key as PubKey @@ -126,7 +126,7 @@ const class JJwk : Jwk else if (pubKey.algorithm == "RSA") { keyParams := JwRsaPubKey.bufToJwk(pubKey.encoded) - jwk = jwk.addAll(keyParams) + jwk = jwk.addAll(keyParams) jwk[JwkConst.AlgorithmHeader] = JwsAlgorithm.fromKeyAndDigest("RSA", digest).toStr jwk[JwkConst.KeyTypeHeader] = "RSA" } @@ -199,7 +199,7 @@ internal enum class JwsKeyType { kty := key[JwkConst.KeyTypeHeader] if (kty == null) return null - type := JwsKeyType.vals.find |JwsKeyType v->Bool| { return v.toStr == kty } + type := JwsKeyType.vals.find |JwsKeyType v->Bool| { return v.toStr == kty } return type == null ? throw Err("JWK kty invalid type") : type } @@ -231,7 +231,7 @@ internal enum class JwsUse ** JwPubKey ************************************************************************** -internal mixin JwPubKey +internal mixin JwPubKey { static PubKey? pem(Buf der, Str algorithm) { @@ -306,12 +306,12 @@ internal class JwRsaPubKey : JwPubKey, JwaConst } static native Buf jwkToBuf(Str mod, Str exp) - + static native Str:Obj bufToJwk(Buf key) private static Buf der(Str:Obj jwk) { - mod := jwk[ModulusParameter] as Str + mod := jwk[ModulusParameter] as Str exp := jwk[ExponentParameter] as Str return jwkToBuf(mod, exp) } @@ -368,7 +368,7 @@ internal class JwEcPubKey : JwPubKey, JwaConst if(!map.containsKey(XCoordParameter)) throw Err("JWK missing EC X coordinate parameter (${XCoordParameter})") if(!map.containsKey(YCoordParameter)) throw Err("JWK missing EC Y coordinate parameter (${YCoordParameter})") if(!map.containsKey(CurveParameter)) throw Err("JWK missing EC Curve parameter (${CurveParameter})") - + return pem(der(map), algorithm) } @@ -378,7 +378,7 @@ internal class JwEcPubKey : JwPubKey, JwaConst private static Buf der(Str:Obj jwk) { - x := jwk[XCoordParameter] as Str + x := jwk[XCoordParameter] as Str y := jwk[YCoordParameter] as Str crv := jwk[CurveParameter] as Str return jwkToBuf(x, y, crv) @@ -417,10 +417,11 @@ internal class JwHmacKey : JwaConst if(!map.containsKey(KeyValueParameter)) throw Err("JWK missing Key Value Parameter (${KeyValueParameter})") - strKey := map[KeyValueParameter] as Str + strKey := map[KeyValueParameter] as Str algorithmName := "Hmac" + JwsAlgorithm.fromParameters(map).digest return JMacKey.load(strKey.toBuf, algorithmName) } -} \ No newline at end of file +} + diff --git a/src/cryptoJava/java/JMacKey.java b/src/cryptoJava/java/JMacKey.java index fdd50eb91..84f0cd890 100644 --- a/src/cryptoJava/java/JMacKey.java +++ b/src/cryptoJava/java/JMacKey.java @@ -3,7 +3,7 @@ // Licensed under the Academic Free License version 3.0 // // History: -// 26 March 2024 Ross Schwalm Creation +// 26 Mar 2024 Ross Schwalm Creation // package fan.cryptoJava; @@ -35,7 +35,7 @@ public static JMacKey load(Buf key, String algorithm) catch (NoSuchAlgorithmException e) { throw Err.make("Unknown MAC algorithm: " + algorithm, e); - } + } catch (InvalidKeyException e) { throw Err.make("Invalid key", e); @@ -138,3 +138,4 @@ public JMacKey updateI8(long i) public JMacKey reset() { this.mac.reset(); return this; } } + diff --git a/src/cryptoJava/java/JwEcPubKeyPeer.java b/src/cryptoJava/java/JwEcPubKeyPeer.java index ce99945ea..b214a4625 100644 --- a/src/cryptoJava/java/JwEcPubKeyPeer.java +++ b/src/cryptoJava/java/JwEcPubKeyPeer.java @@ -3,7 +3,7 @@ // Licensed under the Academic Free License version 3.0 // // History: -// 26 March 2024 Ross Schwalm Creation +// 26 Mar 2024 Ross Schwalm Creation // package fan.cryptoJava; @@ -27,7 +27,7 @@ import java.util.Map; /* - * + * * This source also used for referencing parameters: https://safecurves.cr.yp.to/base.html */ public class JwEcPubKeyPeer @@ -37,7 +37,7 @@ public class JwEcPubKeyPeer private static int COFACTOR = 1; - // + // // NIST P-256 // https://neuromancer.sk/std/nist/P-256 // @@ -48,29 +48,29 @@ public class JwEcPubKeyPeer private static String NIST_P256_X = "48439561293906451759052585252797914202762949526041747995844080717082404635286"; private static String NIST_P256_Y = "36134250956749795798585127919587881956611106672985015071877198253568414405109"; private static String NIST_P256_N = "115792089210356248762697446949407573529996955224135760342422259061068512044369"; - + private static final ECParameterSpec NIST_P256 = new ECParameterSpec( new EllipticCurve(new ECFieldFp(new BigInteger(NIST_P256_P)), new BigInteger(NIST_P256_A), new BigInteger(NIST_P256_B)), new ECPoint(new BigInteger(NIST_P256_X),new BigInteger(NIST_P256_Y)), new BigInteger(NIST_P256_N), COFACTOR); - // + // // NIST P-384 // https://neuromancer.sk/std/nist/P-384 // private static String NIST_P384_JWK_NAME = "P-384"; - private static String NIST_P384_P = "394020061963944792122790401001436138050797392704654466679482934042457217714968" + + private static String NIST_P384_P = "394020061963944792122790401001436138050797392704654466679482934042457217714968" + "70329047266088258938001861606973112319"; - private static String NIST_P384_A = "394020061963944792122790401001436138050797392704654466679482934042457217714968" + + private static String NIST_P384_A = "394020061963944792122790401001436138050797392704654466679482934042457217714968" + "70329047266088258938001861606973112316"; - private static String NIST_P384_B = "275801935599597058778490118403890480930569058563615685214287073019886892413098" + + private static String NIST_P384_B = "275801935599597058778490118403890480930569058563615685214287073019886892413098" + "60865136260764883745107765439761230575"; - private static String NIST_P384_X = "262470350957996892686231567445669818918529234911092133878156159009255188547380" + + private static String NIST_P384_X = "262470350957996892686231567445669818918529234911092133878156159009255188547380" + "50089022388053975719786650872476732087"; - private static String NIST_P384_Y = "832571096148902998554675128952010817928785304886131559470920590248050319988441" + + private static String NIST_P384_Y = "832571096148902998554675128952010817928785304886131559470920590248050319988441" + "9224438643760392947333078086511627871"; - private static String NIST_P384_N = "394020061963944792122790401001436138050797392704654466679469052796276593991132" + + private static String NIST_P384_N = "394020061963944792122790401001436138050797392704654466679469052796276593991132" + "63569398956308152294913554433653942643"; private static final ECParameterSpec NIST_P384 = new ECParameterSpec( @@ -79,22 +79,22 @@ public class JwEcPubKeyPeer new BigInteger(NIST_P384_N), COFACTOR); - // + // // NIST P-521 // https://neuromancer.sk/std/nist/P-521 // private static String NIST_P521_JWK_NAME = "P-521"; - private static String NIST_P521_P = "686479766013060971498190079908139321726943530014330540939446345918554318339765" + + private static String NIST_P521_P = "686479766013060971498190079908139321726943530014330540939446345918554318339765" + "6052122559640661454554977296311391480858037121987999716643812574028291115057151"; - private static String NIST_P521_A = "686479766013060971498190079908139321726943530014330540939446345918554318339765" + + private static String NIST_P521_A = "686479766013060971498190079908139321726943530014330540939446345918554318339765" + "6052122559640661454554977296311391480858037121987999716643812574028291115057148"; - private static String NIST_P521_B = "109384903807373427451111239076680556993620759895168374899458639449595311615073" + + private static String NIST_P521_B = "109384903807373427451111239076680556993620759895168374899458639449595311615073" + "5016013708737573759623248592132296706313309438452531591012912142327488478985984"; - private static String NIST_P521_X = "266174080205021706322876871672336096072985916875697314770667136841880294499642" + + private static String NIST_P521_X = "266174080205021706322876871672336096072985916875697314770667136841880294499642" + "7808491545080627771902352094241225065558662157113545570916814161637315895999846"; - private static String NIST_P521_Y = "375718002577002046354550722449118360359445513476976248669456777961554447744055" + - "6316691234405012945539562144444537289428522585666729196580810124344277578376784"; - private static String NIST_P521_N = "686479766013060971498190079908139321726943530014330540939446345918554318339765" + + private static String NIST_P521_Y = "375718002577002046354550722449118360359445513476976248669456777961554447744055" + + "6316691234405012945539562144444537289428522585666729196580810124344277578376784"; + private static String NIST_P521_N = "686479766013060971498190079908139321726943530014330540939446345918554318339765" + "5394245057746333217197532963996371363321113864768612440380340372808892707005449"; private static final ECParameterSpec NIST_P521 = new ECParameterSpec( @@ -103,7 +103,7 @@ public class JwEcPubKeyPeer new BigInteger(NIST_P521_N), COFACTOR); - static + static { curves.put(NIST_P256_JWK_NAME, NIST_P256); curveNames.put(NIST_P256.getCurve(), NIST_P256_JWK_NAME); @@ -114,9 +114,9 @@ public class JwEcPubKeyPeer } public static JwEcPubKeyPeer make(JwEcPubKey self) { return new JwEcPubKeyPeer(); } - + public static Buf jwkToBuf(String xBase64, String yBase64, String curve) throws NoSuchAlgorithmException, InvalidKeySpecException - { + { byte[] xBytes = Base64.getUrlDecoder().decode(xBase64); byte[] yBytes = Base64.getUrlDecoder().decode(yBase64); @@ -133,7 +133,7 @@ public static Buf jwkToBuf(String xBase64, String yBase64, String curve) throws } public static fan.sys.Map bufToJwk(Buf key) throws NoSuchAlgorithmException, InvalidKeySpecException - { + { KeyFactory keyFactory = KeyFactory.getInstance("EC"); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key.unsafeArray()); ECPublicKey ecPub = (ECPublicKey) keyFactory.generatePublic(keySpec); @@ -150,7 +150,7 @@ public static fan.sys.Map bufToJwk(Buf key) throws NoSuchAlgorithmException, Inv fan.sys.Map jwk = new fan.sys.Map(Sys.StrType, Sys.ObjType); jwk.set("x", Base64.getUrlEncoder().encodeToString(xBytes)); jwk.set("y", Base64.getUrlEncoder().encodeToString(yBytes)); - jwk.set("crv", getName(curve)); + jwk.set("crv", getName(curve)); return jwk; } @@ -164,4 +164,5 @@ private static String getName(EllipticCurve curve) { return curveNames.get(curve); } -} \ No newline at end of file +} + diff --git a/src/cryptoJava/java/JwRsaPubKeyPeer.java b/src/cryptoJava/java/JwRsaPubKeyPeer.java index e94d76956..3aaa6b013 100644 --- a/src/cryptoJava/java/JwRsaPubKeyPeer.java +++ b/src/cryptoJava/java/JwRsaPubKeyPeer.java @@ -3,7 +3,7 @@ // Licensed under the Academic Free License version 3.0 // // History: -// 26 March 2024 Ross Schwalm Creation +// 26 Mar 2024 Ross Schwalm Creation // package fan.cryptoJava; @@ -23,9 +23,9 @@ public class JwRsaPubKeyPeer { public static JwRsaPubKeyPeer make(JwRsaPubKey self) { return new JwRsaPubKeyPeer(); } - + public static Buf jwkToBuf(String modBase64, String expBase64) throws NoSuchAlgorithmException, InvalidKeySpecException - { + { byte[] modBytes = Base64.getUrlDecoder().decode(modBase64); byte[] expBytes = Base64.getUrlDecoder().decode(expBase64); RSAPublicKeySpec spec = new RSAPublicKeySpec(new BigInteger(1, modBytes), new BigInteger(1, expBytes)); @@ -33,17 +33,18 @@ public static Buf jwkToBuf(String modBase64, String expBase64) throws NoSuchAlgo } public static Map bufToJwk(Buf key) throws NoSuchAlgorithmException, InvalidKeySpecException - { + { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key.unsafeArray()); RSAPublicKey rsaPub = (RSAPublicKey) keyFactory.generatePublic(keySpec); byte[] modBytes = rsaPub.getModulus().toByteArray(); - byte[] expBytes = rsaPub.getPublicExponent().toByteArray(); + byte[] expBytes = rsaPub.getPublicExponent().toByteArray(); Map jwk = new Map(Sys.StrType, Sys.ObjType); jwk.set("n", Base64.getUrlEncoder().encodeToString(modBytes)); jwk.set("e", Base64.getUrlEncoder().encodeToString(expBytes)); return jwk; } -} \ No newline at end of file +} + diff --git a/src/doc/docIntro/doc/ChangeLog.fandoc b/src/doc/docIntro/doc/ChangeLog.fandoc index f94827b5e..60862d6b1 100644 --- a/src/doc/docIntro/doc/ChangeLog.fandoc +++ b/src/doc/docIntro/doc/ChangeLog.fandoc @@ -9,6 +9,7 @@ *Build 1.0.80 (working)* - New ECMA class-based JavaScript design - Move fwt pods into separate repo +- Crypto JWT and JWK APIs - Actor queue overflow limits - Add Doc.elemFromPos, elemsFromPos - Add Event.keyChar