1 module jwtd.jwt_botan; 2 3 import jwtd.jwt; 4 5 version (UseBotan) { 6 7 import botan.rng.auto_rng; 8 import botan.mac.hmac; 9 import botan.hash.hash; 10 import botan.hash.sha2_32 : SHA256; 11 import botan.hash.sha2_64 : SHA384, SHA512; 12 import memutils.unique; 13 14 string sign(string msg, string key, JWTAlgorithm algo = JWTAlgorithm.HS256) { 15 ubyte[] sign; 16 17 void sign_hs(HashFunction hashFun) { 18 Unique!HMAC hmac = new HMAC(hashFun); 19 20 hmac.setKey(cast(const(ubyte)*)key.ptr, key.length); 21 hmac.update(msg); 22 sign = hmac.finished()[].dup; 23 } 24 25 void sign_rs(string emsaName) { 26 import botan.filters.data_src; 27 import botan.pubkey.algo.rsa; 28 29 Unique!AutoSeededRNG rng = new AutoSeededRNG; 30 auto privKey = loadKey(cast(DataSource)DataSourceMemory(key), *rng); 31 auto signer = PKSigner(privKey, emsaName); 32 sign = signer.signMessage(cast(const(ubyte)*)msg.ptr, msg.length, *rng)[].dup; 33 } 34 35 void sign_es(string emsaName) { 36 import botan.filters.data_src; 37 import botan.pubkey.algo.ecdsa; 38 39 Unique!AutoSeededRNG rng = new AutoSeededRNG; 40 auto privKey = loadKey(cast(DataSource)DataSourceMemory(key), *rng); 41 auto signer = PKSigner(privKey, emsaName, DER_SEQUENCE); 42 sign = signer.signMessage(cast(const(ubyte)*)msg.ptr, msg.length, *rng)[].dup; 43 } 44 45 switch(algo) { 46 case JWTAlgorithm.NONE: { 47 break; 48 } 49 case JWTAlgorithm.HS256: { 50 Unique!SHA256 hash = new SHA256(); 51 sign_hs(*hash); 52 break; 53 } 54 case JWTAlgorithm.HS384: { 55 Unique!SHA384 hash = new SHA384(); 56 sign_hs(*hash); 57 break; 58 } 59 case JWTAlgorithm.HS512: { 60 Unique!SHA512 hash = new SHA512(); 61 sign_hs(*hash); 62 break; 63 } 64 case JWTAlgorithm.RS256: 65 sign_rs("EMSA3(SHA-256)"); 66 break; 67 case JWTAlgorithm.RS384: 68 sign_rs("EMSA3(SHA-384)"); 69 break; 70 case JWTAlgorithm.RS512: 71 sign_rs("EMSA3(SHA-512)"); 72 break; 73 case JWTAlgorithm.ES256: 74 sign_es("EMSA1(SHA-256)"); 75 break; 76 case JWTAlgorithm.ES384: 77 sign_es("EMSA1(SHA-384)"); 78 break; 79 case JWTAlgorithm.ES512: 80 sign_es("EMSA1(SHA-512)"); 81 break; 82 default: 83 throw new SignException("Wrong algorithm."); 84 } 85 86 return cast(string)sign; 87 } 88 89 bool verifySignature(string signature, string signing_input, string key, JWTAlgorithm algo = JWTAlgorithm.HS256) { 90 91 bool verify_rs(string emsaName) { 92 import x509 = botan.pubkey.x509_key; 93 import botan.pubkey.algo.rsa; 94 import botan.filters.data_src; 95 96 auto pubKey = x509.loadKey(cast(DataSource)DataSourceMemory(key)); 97 auto verifier = PKVerifier(pubKey, emsaName); 98 return verifier.verifyMessage( 99 cast(const(ubyte)*)signing_input.ptr, signing_input.length, 100 cast(const(ubyte)*)signature.ptr, signature.length); 101 } 102 103 bool verify_es(string emsaName) { 104 import x509 = botan.pubkey.x509_key; 105 import botan.pubkey.algo.ecdsa; 106 import botan.filters.data_src; 107 108 auto pubKey = x509.loadKey(cast(DataSource)DataSourceMemory(key)); 109 auto verifier = PKVerifier(pubKey, emsaName, DER_SEQUENCE); 110 return verifier.verifyMessage( 111 cast(const(ubyte)*)signing_input.ptr, signing_input.length, 112 cast(const(ubyte)*)signature.ptr, signature.length); 113 } 114 115 switch(algo) { 116 case JWTAlgorithm.NONE: 117 return key.length == 0; 118 case JWTAlgorithm.HS256: 119 case JWTAlgorithm.HS384: 120 case JWTAlgorithm.HS512: 121 return signature == sign(signing_input, key, algo); 122 case JWTAlgorithm.RS256: 123 return verify_rs("EMSA3(SHA-256)"); 124 case JWTAlgorithm.RS384: 125 return verify_rs("EMSA3(SHA-384)"); 126 case JWTAlgorithm.RS512: 127 return verify_rs("EMSA3(SHA-512)"); 128 case JWTAlgorithm.ES256: 129 return verify_es("EMSA1(SHA-256)"); 130 case JWTAlgorithm.ES384: 131 return verify_es("EMSA1(SHA-384)"); 132 case JWTAlgorithm.ES512: 133 return verify_es("EMSA1(SHA-512)"); 134 default: 135 throw new VerifyException("Wrong algorithm."); 136 } 137 } 138 }