Beispiel #1
0
        private byte[] AES_KeyUnwrap(JWK keyObject, int keySize, byte[] rgbKey = null)
        {
            if (keyObject != null)
            {
                if (keyObject.AsString("kty") != "oct")
                {
                    return(null);
                }
                rgbKey = keyObject.AsBytes("k");
            }

            if (rgbKey != null && rgbKey.Length != keySize / 8)
            {
                throw new JoseException("Key is not the correct size");
            }

            AesWrapEngine foo        = new AesWrapEngine();
            KeyParameter  parameters = new KeyParameter(rgbKey);

            foo.Init(false, parameters);
            _payload = foo.Unwrap(_rgbEncrypted, 0, _rgbEncrypted.Length);
            return(_payload);
        }
Beispiel #2
0
        private byte[] ECDH_GenerateSecret(JWK key, EncryptMessage msg)
        {
            JWK epk;

            if ((key.AsString("kty") != "EC") && (key.AsString("kty") != "OKP"))
            {
                throw new JoseException("Not an EC or OKP Key");
            }

            if (_mSenderKey != null)
            {
                epk = _mSenderKey;
            }
            else
            {
                CBORObject epkT = FindAttr("epk", msg);
                if (epkT == null)
                {
                    throw new JoseException("No Ephemeral key");
                }
                epk = new JWK(epkT);
            }

            if (epk.AsString("crv") != key.AsString("crv"))
            {
                throw new JoseException("not a match of curves");
            }

            if (key.AsString("kty") == "EC")
            {
                //  Get the curve

                X9ECParameters     p          = NistNamedCurves.GetByName(key.AsString("crv"));
                ECDomainParameters parameters = new ECDomainParameters(p.Curve, p.G, p.N, p.H);

                Org.BouncyCastle.Math.EC.ECPoint pubPoint = p.Curve.CreatePoint(epk.AsBigInteger("x"), epk.AsBigInteger("y"));
                ECPublicKeyParameters            pub      = new ECPublicKeyParameters(pubPoint, parameters);

                ECPrivateKeyParameters priv = new ECPrivateKeyParameters(key.AsBigInteger("d"), parameters);

                IBasicAgreement e1 = new ECDHBasicAgreement();
                e1.Init(priv);

                BigInteger k1 = e1.CalculateAgreement(pub);

                return(k1.ToByteArrayUnsigned());
            }
            else
            {
                switch (epk.AsString("crv"))
                {
                case "X25519": {
                    X25519PublicKeyParameters pub =
                        new X25519PublicKeyParameters(epk.AsBytes("x"), 0);
                    X25519PrivateKeyParameters priv =
                        new X25519PrivateKeyParameters(key.AsBytes("d"), 0);

                    X25519Agreement agree = new X25519Agreement();
                    agree.Init(priv);
                    byte[] secret = new byte[32];
                    agree.CalculateAgreement(pub, secret, 0);
                    return(secret);
                }

                default:
                    throw new JoseException("Unsupported curve");
                }
            }
        }
Beispiel #3
0
        public Recipient(JWK key, string algorithm = null, EncryptMessage msg = null)
        {
            if (algorithm == null && key.ContainsName("alg"))
            {
                algorithm = key.AsString("alg");
            }
            if (algorithm != null)
            {
                switch (algorithm)
                {
                case "dir": // Direct encryption mode
                case "A128GCM":
                case "A192GCM":
                case "A256GCM":
                    if (key.AsString("kty") != "oct")
                    {
                        throw new JoseException("Invalid parameters");
                    }
                    RecipientType = RecipientType.Direct;
                    algorithm     = "dir";
                    break;

                case "ECDH-ES":
#if DEBUG
                case "ECDH-SS":
#endif // DEBUG
                    if ((key.AsString("kty") != "EC") && (key.AsString("kty") != "OKP"))
                    {
                        throw new JoseException("Invalid Parameters");
                    }
                    RecipientType = RecipientType.KeyAgreeDirect;
                    break;

                case "RSA1_5":
                case "RSA-OAEP":
                case "RSA-OAEP-256":
                    if (key.AsString("kty") != "RSA")
                    {
                        throw new JoseException("Invalid Parameter");
                    }
                    RecipientType = RecipientType.KeyTransport;
                    break;

                case "A128KW":
                case "A192KW":
                case "A256KW":
                case "A128GCMKW":
                case "A192GCMKW":
                case "A256GCMKW":
                    if (key.AsString("kty") != "oct")
                    {
                        throw new JoseException("Invalid Parameter");
                    }
                    RecipientType = RecipientType.KeyWrap;
                    break;

                case "ECDH-ES+A128KW":
                case "ECDH-ES+A192KW":
                case "ECDH-ES+A256KW":
                    if ((key.AsString("kty") != "EC") && (key.AsString("kty") != "OKP"))
                    {
                        throw new JoseException("Invalid Parameter");
                    }
                    RecipientType = RecipientType.KeyAgree;
                    break;

                case "PBES2-HS256+A128KW":
                case "PBES2-HS384+A192KW":
                case "PBES2-HS512+A256KW":
                    if (key.AsString("kty") != "oct")
                    {
                        throw new JoseException("Invalid Parameter");
                    }
                    RecipientType = RecipientType.Password;
                    break;

                default:
                    throw new JoseException("Unrecognized recipient algorithm");
                }

                _mKey = key;
                if (FindAttr("alg", msg) == null)
                {
                    AddAttribute("alg", algorithm, UNPROTECTED);
                }
            }
            else
            {
                switch (key.AsString("kty"))
                {
                case "oct":
                    RecipientType = RecipientType.KeyWrap;
                    switch (key.AsBytes("k").Length)
                    {
                    case 128 / 8:
                        algorithm = "A128KW";
                        break;

                    case 192 / 8:
                        algorithm = "A192KW";
                        break;

                    case 256 / 8:
                        algorithm = "A256KW";
                        break;

                    default:
                        throw new JoseException("Key size does not match any algorthms");
                    }

                    break;

                case "RSA":
                    RecipientType = RecipientType.KeyTransport;
                    algorithm     = "RSA-OAEP-256";
                    break;

                case "EC":
                    RecipientType = RecipientType.KeyAgree;
                    algorithm     = "ECDH-ES+A128KW";
                    break;
                }

                if (FindAttr("alg", msg) == null)
                {
                    AddAttribute("alg", algorithm, UNPROTECTED);
                }

                _mKey = key;
            }

            if (key.ContainsName("use"))
            {
                string usage = key.AsString("use");
                if (usage != "enc")
                {
                    throw new JoseException("Key cannot be used for encrytion");
                }
            }

            if (key.ContainsName("key_ops"))
            {
                string usageObject = key.AsString("key_ops");
                bool   validUsage  = false;

                string[] usageArray = usageObject.Split(',');
                for (int i = 0; i < usageArray.Length; i++)
                {
                    switch (usageArray[i])
                    {
                    case "encrypt":
                    case "keywrap":
                        validUsage = true;
                        break;
                    }
                }

                if (!validUsage)
                {
                    throw new JoseException("Key cannot be used for encryption");
                }
            }

            if (key.ContainsName("kid") && (FindAttr("kid", msg) == null))
            {
                AddAttribute("kid", key.AsString("kid"), UNPROTECTED);
            }
        }
Beispiel #4
0
        public byte[] GetKey(string alg, EncryptMessage msg)
        {
            if (_mKey == null)
            {
                return(null);
            }

            try {
                string keyAlgorithm = _mKey.AsString("alg");
                if (alg != keyAlgorithm)
                {
                    throw new JoseException("Algorithm mismatch between message and key");
                }
            }
            catch (Exception) {
                // ignored
            }

            //  Figure out how longer the needed key is:

            int cbitKey;

            switch (alg)
            {
            case "A128GCM":
            case "AES-128-CCM-64":
                cbitKey = 128;
                break;

            case "A192GCM":
                cbitKey = 196;
                break;

            case "A256GCM":
            case "HS256":
                cbitKey = 256;
                break;

            case "HS384":
                cbitKey = 384;
                break;

            case "HS512":
                cbitKey = 512;
                break;

            case "A128CBC-HS256":
                cbitKey = 128 * 2;
                break;

            case "A192CBC-HS256":
                cbitKey = 192 * 2;
                break;

            case "A256CBC-HS256":
                cbitKey = 256 * 2;
                break;

            default:
                throw new JoseException("NYI");
            }

            string algKeyManagement = FindAttr("alg", msg).AsString();

            switch (algKeyManagement)
            {
            case "dir":
                if (_mKey.AsString("kty") != "oct")
                {
                    throw new JoseException("Key and key managment algorithm don't match");
                }
                byte[] rgb = _mKey.AsBytes("k");
                if (rgb.Length * 8 != cbitKey)
                {
                    throw new JoseException("Incorrect key size");
                }
                return(rgb);

            case "ECDH-ES": {
                if ((_mKey.AsString("kty") != "EC") && (_mKey.AsString("kty") != "OKP"))
                {
                    throw new JoseException("Key and key management algorithm don't match");
                }

                ECDH_GenerateEphemeral(msg);

                byte[] rgbSecret = ECDH_GenerateSecret(_mKey, msg);

                return(Kdf(rgbSecret, msg, cbitKey, alg));
            }

            case "ECDH-SS": {
                if (_mKey.AsString("kty") != "EC")
                {
                    throw new JoseException("Key and key managment algorithm don't match");
                }
                if (FindAttribute("apu") == null)
                {
                    byte[] rgbApu = new byte[512 / 8];
                    Message.s_PRNG.NextBytes(rgbApu);
                    AddAttribute("apu", CBORObject.FromObject(rgbApu), UNPROTECTED);
                }

                byte[] rgbSecret = ECDH_GenerateSecret(_mKey, msg);
                return(Kdf(rgbSecret, msg, cbitKey, alg));
            }
            }

            throw new JoseException($"NYI: {alg}");
        }
Beispiel #5
0
        public byte[] Decrypt(int cbitKey, EncryptMessage msg)
        {
            JWK key = _mKey;

            if (key == null)
            {
                throw new JoseException("No key specified.");
            }
            string alg;

            alg = FindAttr("alg", msg).AsString();

            switch (alg)
            {
            case "dir":
                if (key.AsString("kty") != "oct")
                {
                    return(null);
                }
                return(key.AsBytes("k"));

            case "ECDH-ES": {
                if ((key.AsString("kty") != "EC") && (key.AsString("kty") != "OKP"))
                {
                    return(null);
                }

                byte[] secret = Ecdh(key, msg);
                byte[] kwKey  = Kdf(secret, msg, cbitKey, FindAttr("enc", msg).AsString());
                return(kwKey);
            }

            case "A128KW":
            case "A192KW":
            case "A256KW":
                if (key.AsString("kty") != "oct")
                {
                    return(null);
                }

                return(AES_KeyWrap(key.AsBytes("k")));

            case "A128GCMKW":
            case "A192GCMKW":
            case "A256GCMKW":
                if (key.AsString("kty") != "oct")
                {
                    return(null);
                }
                return(AESGCM_KeyWrap(key.AsBytes("k"), msg));

            case "PBES2-HS256+A128KW":
            case "PBES2-HS384+A192KW":
            case "PBES2-HS512+A256KW": {
                if (key.AsString("kty") != "oct")
                {
                    return(null);
                }
                byte[] saltInput = Message.base64urldecode(FindAttr("p2s", msg).AsString());
                byte[] algBytes  = Encoding.UTF8.GetBytes(alg);
                byte[] salt      = new byte[alg.Length + 1 + saltInput.Length];
                Array.Copy(algBytes, salt, algBytes.Length);
                Array.Copy(saltInput, 0, salt, algBytes.Length + 1, saltInput.Length);
                int iterCount = FindAttr("p2c", msg).AsInt32();

                byte[] rgbSecret = PBKDF2(key.AsBytes("k"), salt, iterCount, 256 / 8, new Sha512Digest());

                return(AES_KeyWrap(rgbSecret));
            }

            case "RSA-OAEP-256":
            case "RSA-OAEP": {
                IAsymmetricBlockCipher cipher = new OaepEncoding(new RsaEngine(), alg == "RSA-OAEP" ? (IDigest) new Sha1Digest() : new Sha256Digest());
                RsaKeyParameters       prv    = new RsaPrivateCrtKeyParameters(key.AsBigInteger("n"), key.AsBigInteger("e"), key.AsBigInteger("d"), key.AsBigInteger("p"), key.AsBigInteger("q"),
                                                                               key.AsBigInteger("dp"), key.AsBigInteger("dq"), key.AsBigInteger("qi"));

                cipher.Init(false, prv);
                byte[] outBytes = cipher.ProcessBlock(_rgbEncrypted, 0, _rgbEncrypted.Length);

                return(outBytes);
            }

            case "ECDH-ES+A128KW": {
                if ((key.AsString("kty") != "EC") && (key.AsString("kty") != "OKP"))
                {
                    return(null);
                }

                byte[] secret = Ecdh(key, msg);
                byte[] kwKey  = Kdf(secret, msg, 128, FindAttr("alg", msg).AsString());
                return(AES_KeyWrap(kwKey));
            }

            case "ECDH-ES+A192KW": {
                if (key.AsString("kty") != "EC")
                {
                    return(null);
                }

                byte[] secret = Ecdh(key, msg);
                byte[] kwKey  = Kdf(secret, msg, 192, FindAttr("alg", msg).AsString());
                return(AES_KeyWrap(kwKey));
            }

            case "ECDH-ES+A256KW": {
                if (key.AsString("kty") != "EC")
                {
                    return(null);
                }

                byte[] secret = Ecdh(key, msg);
                byte[] kwKey  = Kdf(secret, msg, 256, FindAttr("alg", msg).AsString());
                return(AES_KeyWrap(kwKey));
            }

            case "RSA1_5": {
                if (key.AsString("kty") != "RSA")
                {
                    return(null);
                }

                IAsymmetricBlockCipher cipher = new Pkcs1Encoding(new RsaEngine());
                RsaKeyParameters       prv    = new RsaPrivateCrtKeyParameters(key.AsBigInteger("n"), key.AsBigInteger("e"), key.AsBigInteger("d"), key.AsBigInteger("p"), key.AsBigInteger("q"),
                                                                               key.AsBigInteger("dp"), key.AsBigInteger("dq"), key.AsBigInteger("qi"));

                cipher.Init(false, prv);
                return(cipher.ProcessBlock(_rgbEncrypted, 0, _rgbEncrypted.Length));
            }
            }

            return(null);
        }
Beispiel #6
0
        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);
        }