public CBORObject EncodeToJSON(byte[] body) { CBORObject obj = CBORObject.NewMap(); if (protectedB64 != null) { obj.Add("protected", protectedB64); } else if (ProtectedMap.Count > 0) { protectedB64 = Message.base64urlencode(Encoding.UTF8.GetBytes(JSON.ToJsonString(ProtectedMap))); obj.Add("protected", protectedB64); } if (UnprotectedMap.Count > 0) { obj.Add("header", UnprotectedMap); // Add unprotected attributes } String str = ""; if (ProtectedMap.ContainsKey("b64") && ProtectedMap["b64"].AsBoolean() == false) { str += protectedB64 + "." + Encoding.UTF8.GetString(body); } else { str += protectedB64 + "." + Message.base64urlencode(body); } #if DEBUG ToBeSigned = str; #endif obj.Add("signature", Message.base64urlencode(Sign(Encoding.UTF8.GetBytes(str)))); return(obj); }
/// <summary> /// Encrypt the message based on attributes and recipients. /// </summary> public virtual void Encrypt() { string alg = null; // Get the algorithm we are using - the default is AES GCM try { alg = FindAttribute("enc").AsString(); } catch { foreach (Recipient r in RecipientList) { CBORObject alg2 = r.FindAttribute("enc"); if (alg2 != null) { if (alg2.Type != CBORType.TextString || (alg != null && alg != alg2.AsString())) { throw new JoseException("Multiple content encryption algorithms have been specified."); } alg = alg2.AsString(); } } if (alg == null) { throw new JoseException("Content encryption algorithm has not been specified."); } } byte[] contentKey = null; // Determine if we are doing a direct encryption int recipientTypes = 0; if (RecipientList.Count == 0) { throw new JoseException("Must have at least one recipient for the message"); } foreach (Recipient key in RecipientList) { switch (key.RecipientType) { case RecipientType.Direct: case RecipientType.KeyAgreeDirect: if ((recipientTypes & 1) != 0) { throw new JoseException("It is not legal to have two direct recipients in a message"); } recipientTypes |= 1; contentKey = key.GetKey(alg, this); break; default: recipientTypes |= 2; break; } } if (recipientTypes == 3) { throw new JoseException("It is not legal to mix direct and indirect recipients in a message"); } if (contentKey == null) { switch (alg) { case "A128GCM": case "AES-128-CCM-64": contentKey = new byte[128 / 8]; break; case "A192GCM": case "AES192GCM": contentKey = new byte[192 / 8]; break; case "A256GCM": case "AES256GCM": contentKey = new byte[256 / 8]; break; case "A128CBC-HS256": contentKey = new byte[2 * 128 / 8]; break; case "A192CBC-HS256": contentKey = new byte[2 * 192 / 8]; break; case "A256CBC-HS256": contentKey = new byte[2 * 256 / 8]; break; default: throw new JoseException($"Unrecognized content encryption algorithm '{alg}'"); } s_PRNG.NextBytes(contentKey); } foreach (Recipient key in RecipientList) { key.SetContent(contentKey); key.Encrypt(this); } // Encode the protected attributes if there are any if (ProtectedMap.Count > 0) { _strProtected = base64urlencode(Encoding.UTF8.GetBytes(ProtectedMap.ToString())); } byte[] saveContent = payload; if (ProtectedMap.ContainsKey("zip")) { MemoryStream stm2 = new MemoryStream(); DeflateStream zipStm = new DeflateStream(stm2, CompressionMode.Compress); zipStm.Write(payload, 0, payload.Length); zipStm.Close(); payload = stm2.GetBuffer(); } switch (alg) { case "A128GCM": case "A192GCM": case "A256GCM": AES_GCM_Encrypt(contentKey); break; case "AES-128-CCM-64": AES_CCM(contentKey); break; case "A128CBC-HS256": case "A192CBC-HS256": case "A256CBC-HS256": AES_CBC_MAC_Encrypt(alg, contentKey); break; default: throw new JoseException("Internal Error: We should never get here."); } payload = saveContent; }
public bool Verify(SignMessage msg) { string alg = FindAttribute("alg").AsString(); JWK key = keyToSign; IDigest digest; IDigest digest2; switch (alg) { case "RS256": case "ES256": case "PS256": case "HS256": digest = new Sha256Digest(); digest2 = new Sha256Digest(); break; case "RS384": case "ES384": case "PS384": case "HS384": digest = new Sha384Digest(); digest2 = new Sha384Digest(); break; case "RS512": case "ES512": case "PS512": case "HS512": digest = new Sha512Digest(); digest2 = new Sha512Digest(); break; case "EdDSA": digest = null; digest2 = null; break; default: throw new JoseException("Unknown signature algorithm"); } // byte[] toBeSigned; string str = ""; string body = Encoding.UTF8.GetString(msg.payloadB64); if (ProtectedMap.ContainsKey("b64") && ProtectedMap["b64"].AsBoolean() == false) { str += protectedB64 + "." + body; } else { str += protectedB64 + "." + body; } toBeSigned = Encoding.UTF8.GetBytes(str); switch (alg) { case "RS256": case "RS384": case "RS512": { if (key.AsString("kty") != "RSA") { throw new JoseException("Wrong Key"); } RsaDigestSigner signer = new RsaDigestSigner(digest); RsaKeyParameters pub = new RsaKeyParameters(false, key.AsBigInteger("n"), key.AsBigInteger("e")); signer.Init(false, pub); signer.BlockUpdate(toBeSigned, 0, toBeSigned.Length); if (!signer.VerifySignature(signature)) { throw new JoseException("Message failed to verify"); } } break; case "PS256": case "PS384": case "PS512": { PssSigner signer = new PssSigner(new RsaEngine(), digest, digest2, digest2.GetDigestSize()); RsaKeyParameters pub = new RsaKeyParameters(false, key.AsBigInteger("n"), key.AsBigInteger("e")); signer.Init(false, pub); signer.BlockUpdate(toBeSigned, 0, toBeSigned.Length); if (!signer.VerifySignature(signature)) { throw new JoseException("Message failed to verify"); } } break; case "ES256": case "ES384": case "ES512": { digest.BlockUpdate(toBeSigned, 0, toBeSigned.Length); byte[] o1 = new byte[digest.GetDigestSize()]; digest.DoFinal(o1, 0); if (key.AsString("kty") != "EC") { throw new JoseException("Wrong Key Type"); } ICipherParameters pubKey = keyToSign.AsPublicKey(); ECDsaSigner ecdsa = new ECDsaSigner(); ecdsa.Init(false, pubKey); BigInteger r = new BigInteger(1, signature, 0, signature.Length / 2); BigInteger s = new BigInteger(1, signature, signature.Length / 2, signature.Length / 2); if (!ecdsa.VerifySignature(o1, r, s)) { throw new JoseException("Signature did not validate"); } } break; case "HS256": case "HS384": case "HS512": { HMac hmac = new HMac(digest); KeyParameter K = new KeyParameter(Message.base64urldecode(key.AsString("k"))); hmac.Init(K); hmac.BlockUpdate(toBeSigned, 0, toBeSigned.Length); byte[] resBuf = new byte[hmac.GetMacSize()]; hmac.DoFinal(resBuf, 0); bool fVerify = true; for (int i = 0; i < resBuf.Length; i++) { if (resBuf[i] != signature[i]) { fVerify = false; } } if (!fVerify) { throw new JoseException("Signature did not validate"); } } break; case "EdDSA": { ISigner eddsa; if (key.AsString("kty") != "OKP") { throw new JoseException("Wrong Key Type"); } switch (key.AsString("crv")) { case "Ed25519": { Ed25519PublicKeyParameters privKey = new Ed25519PublicKeyParameters(key.AsBytes("X"), 0); eddsa = new Ed25519Signer(); eddsa.Init(false, privKey); eddsa.BlockUpdate(toBeSigned, 0, toBeSigned.Length); if (!eddsa.VerifySignature(signature)) { throw new JoseException("Signature did not validate"); } break; } default: throw new JoseException("Unknown algorithm"); } break; } default: throw new JoseException("Unknown algorithm"); } return(true); }