public void GetAuthenticatedEncryptorByKeyId_DefersInstantiation_AndReturnsRevocationInfo()
        {
            // Arrange
            var expectedEncryptorInstance1 = new Mock <IAuthenticatedEncryptor>().Object;
            var expectedEncryptorInstance2 = new Mock <IAuthenticatedEncryptor>().Object;

            var key1 = new MyKey(expectedEncryptorInstance: expectedEncryptorInstance1, isRevoked: true);
            var key2 = new MyKey(expectedEncryptorInstance: expectedEncryptorInstance2);

            // Act
            var keyRing = new KeyRing(key2, new[] { key1, key2 });

            // Assert
            bool isRevoked;

            Assert.Equal(0, key1.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance1, keyRing.GetAuthenticatedEncryptorByKeyId(key1.KeyId, out isRevoked));
            Assert.True(isRevoked);
            Assert.Equal(1, key1.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance1, keyRing.GetAuthenticatedEncryptorByKeyId(key1.KeyId, out isRevoked));
            Assert.True(isRevoked);
            Assert.Equal(1, key1.NumTimesCreateEncryptorInstanceCalled);
            Assert.Equal(0, key2.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance2, keyRing.GetAuthenticatedEncryptorByKeyId(key2.KeyId, out isRevoked));
            Assert.False(isRevoked);
            Assert.Equal(1, key2.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance2, keyRing.GetAuthenticatedEncryptorByKeyId(key2.KeyId, out isRevoked));
            Assert.False(isRevoked);
            Assert.Equal(1, key2.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance2, keyRing.DefaultAuthenticatedEncryptor);
            Assert.Equal(1, key2.NumTimesCreateEncryptorInstanceCalled);
        }
        public void Protect_Unprotect_RoundTripsProperly()
        {
            // Arrange
            byte[] plaintext           = new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50 };
            Key    key                 = new Key(Guid.NewGuid(), DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, new AuthenticatedEncryptorConfiguration(new AuthenticatedEncryptionOptions()).CreateNewDescriptor());
            var    keyRing             = new KeyRing(key, new[] { key });
            var    mockKeyRingProvider = new Mock <IKeyRingProvider>();

            mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing);

            var protector = new KeyRingBasedDataProtector(
                keyRingProvider: mockKeyRingProvider.Object,
                logger: null,
                originalPurposes: null,
                newPurpose: "purpose");

            // Act - protect
            byte[] protectedData = protector.Protect(plaintext);
            Assert.NotNull(protectedData);
            Assert.NotEqual(plaintext, protectedData);

            // Act - unprotect
            byte[] roundTrippedPlaintext = protector.Unprotect(protectedData);
            Assert.Equal(plaintext, roundTrippedPlaintext);
        }
        public void Unprotect_KeyRevoked_RevocationDisallowed_ThrowsKeyRevoked()
        {
            // Arrange
            Guid keyId = new Guid("654057ab-2491-4471-a72a-b3b114afda38");

            byte[] protectedData = BuildProtectedDataFromCiphertext(
                keyId: keyId,
                ciphertext: new byte[0]);

            var mockDescriptor = new Mock <IAuthenticatedEncryptorDescriptor>();

            mockDescriptor.Setup(o => o.CreateEncryptorInstance()).Returns(new Mock <IAuthenticatedEncryptor>().Object);

            // the keyring has only one key
            Key key = new Key(keyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object);

            key.SetRevoked();
            var keyRing             = new KeyRing(key, new[] { key });
            var mockKeyRingProvider = new Mock <IKeyRingProvider>();

            mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing);

            IDataProtector protector = new KeyRingBasedDataProtector(
                keyRingProvider: mockKeyRingProvider.Object,
                logger: null,
                originalPurposes: null,
                newPurpose: "purpose");

            // Act & assert
            var ex = ExceptionAssert2.ThrowsCryptographicException(() => protector.Unprotect(protectedData));

            Assert.Equal(Error.Common_KeyRevoked(keyId).Message, ex.Message);
        }
        public void GetAuthenticatedEncryptorByKeyId_DefersInstantiation_AndReturnsRevocationInfo()
        {
            // Arrange
            var expectedEncryptorInstance1 = new Mock<IAuthenticatedEncryptor>().Object;
            var expectedEncryptorInstance2 = new Mock<IAuthenticatedEncryptor>().Object;

            var key1 = new MyKey(expectedEncryptorInstance: expectedEncryptorInstance1, isRevoked: true);
            var key2 = new MyKey(expectedEncryptorInstance: expectedEncryptorInstance2);

            // Act
            var keyRing = new KeyRing(key2, new[] { key1, key2 });

            // Assert
            bool isRevoked;
            Assert.Equal(0, key1.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance1, keyRing.GetAuthenticatedEncryptorByKeyId(key1.KeyId, out isRevoked));
            Assert.True(isRevoked);
            Assert.Equal(1, key1.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance1, keyRing.GetAuthenticatedEncryptorByKeyId(key1.KeyId, out isRevoked));
            Assert.True(isRevoked);
            Assert.Equal(1, key1.NumTimesCreateEncryptorInstanceCalled);
            Assert.Equal(0, key2.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance2, keyRing.GetAuthenticatedEncryptorByKeyId(key2.KeyId, out isRevoked));
            Assert.False(isRevoked);
            Assert.Equal(1, key2.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance2, keyRing.GetAuthenticatedEncryptorByKeyId(key2.KeyId, out isRevoked));
            Assert.False(isRevoked);
            Assert.Equal(1, key2.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance2, keyRing.DefaultAuthenticatedEncryptor);
            Assert.Equal(1, key2.NumTimesCreateEncryptorInstanceCalled);
        }
        public void DefaultKeyId_Prop()
        {
            // Arrange
            var key1 = new MyKey();
            var key2 = new MyKey();

            // Act
            var keyRing = new KeyRing(key2, new[] { key1, key2 });

            // Assert
            Assert.Equal(key2.KeyId, keyRing.DefaultKeyId);
        }
        public void Unprotect_IsNotDefaultKey_Success_RequiresMigration()
        {
            // Arrange
            Guid defaultKeyId  = new Guid("ba73c9ce-d322-4e45-af90-341307e11c38");
            Guid embeddedKeyId = new Guid("9b5d2db3-299f-4eac-89e9-e9067a5c1853");

            byte[] expectedCiphertext = new byte[] { 0x03, 0x05, 0x07, 0x11, 0x13, 0x17, 0x19 };
            byte[] protectedData      = BuildProtectedDataFromCiphertext(embeddedKeyId, expectedCiphertext);
            byte[] expectedAad        = BuildAadFromPurposeStrings(embeddedKeyId, "purpose");
            byte[] expectedPlaintext  = new byte[] { 0x23, 0x29, 0x31, 0x37 };

            var mockEncryptor = new Mock <IAuthenticatedEncryptor>();

            mockEncryptor
            .Setup(o => o.Decrypt(It.IsAny <ArraySegment <byte> >(), It.IsAny <ArraySegment <byte> >()))
            .Returns <ArraySegment <byte>, ArraySegment <byte> >((actualCiphertext, actualAad) =>
            {
                Assert.Equal(expectedCiphertext, actualCiphertext);
                Assert.Equal(expectedAad, actualAad);
                return(expectedPlaintext);
            });
            var mockDescriptor = new Mock <IAuthenticatedEncryptorDescriptor>();

            mockDescriptor.Setup(o => o.CreateEncryptorInstance()).Returns(mockEncryptor.Object);

            Key defaultKey          = new Key(defaultKeyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, new Mock <IAuthenticatedEncryptorDescriptor>().Object);
            Key embeddedKey         = new Key(embeddedKeyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object);
            var keyRing             = new KeyRing(defaultKey, new[] { defaultKey, embeddedKey });
            var mockKeyRingProvider = new Mock <IKeyRingProvider>();

            mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing);

            IDataProtector protector = new KeyRingBasedDataProtector(
                keyRingProvider: mockKeyRingProvider.Object,
                logger: null,
                originalPurposes: null,
                newPurpose: "purpose");

            // Act & assert - IDataProtector
            byte[] retVal = protector.Unprotect(protectedData);
            Assert.Equal(expectedPlaintext, retVal);

            // Act & assert - IPersistedDataProtector
            bool requiresMigration, wasRevoked;

            retVal = ((IPersistedDataProtector)protector).DangerousUnprotect(protectedData,
                                                                             ignoreRevocationErrors: false,
                                                                             requiresMigration: out requiresMigration,
                                                                             wasRevoked: out wasRevoked);
            Assert.Equal(expectedPlaintext, retVal);
            Assert.True(requiresMigration);
            Assert.False(wasRevoked);
        }
        public void DefaultKeyId_Prop()
        {
            // Arrange
            var key1 = new MyKey();
            var key2 = new MyKey();

            // Act
            var keyRing = new KeyRing(key2, new[] { key1, key2 });

            // Assert
            Assert.Equal(key2.KeyId, keyRing.DefaultKeyId);
        }
        public void DefaultKeyIdAndEncryptor_IfDefaultKeyNotPresentInAllKeys()
        {
            // Arrange
            var key1 = new MyKey();
            var key2 = new MyKey();
            var key3 = new MyKey(expectedEncryptorInstance: new Mock<IAuthenticatedEncryptor>().Object);

            // Act
            var keyRing = new KeyRing(key3, new[] { key1, key2 });

            // Assert
            bool unused;
            Assert.Equal(key3.KeyId, keyRing.DefaultKeyId);
            Assert.Equal(key3.CreateEncryptorInstance(), keyRing.GetAuthenticatedEncryptorByKeyId(key3.KeyId, out unused));
        }
        public void DefaultKeyIdAndEncryptor_IfDefaultKeyNotPresentInAllKeys()
        {
            // Arrange
            var key1 = new MyKey();
            var key2 = new MyKey();
            var key3 = new MyKey(expectedEncryptorInstance: new Mock <IAuthenticatedEncryptor>().Object);

            // Act
            var keyRing = new KeyRing(key3, new[] { key1, key2 });

            // Assert
            bool unused;

            Assert.Equal(key3.KeyId, keyRing.DefaultKeyId);
            Assert.Equal(key3.CreateEncryptorInstance(), keyRing.GetAuthenticatedEncryptorByKeyId(key3.KeyId, out unused));
        }
        public void DefaultAuthenticatedEncryptor_Prop_InstantiationIsDeferred()
        {
            // Arrange
            var expectedEncryptorInstance = new Mock <IAuthenticatedEncryptor>().Object;

            var key1 = new MyKey(expectedEncryptorInstance: expectedEncryptorInstance);
            var key2 = new MyKey();

            // Act
            var keyRing = new KeyRing(key1, new[] { key1, key2 });

            // Assert
            Assert.Equal(0, key1.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance, keyRing.DefaultAuthenticatedEncryptor);
            Assert.Equal(1, key1.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance, keyRing.DefaultAuthenticatedEncryptor);
            Assert.Equal(1, key1.NumTimesCreateEncryptorInstanceCalled); // should've been cached
        }
        public void DefaultAuthenticatedEncryptor_Prop_InstantiationIsDeferred()
        {
            // Arrange
            var expectedEncryptorInstance = new Mock<IAuthenticatedEncryptor>().Object;

            var key1 = new MyKey(expectedEncryptorInstance: expectedEncryptorInstance);
            var key2 = new MyKey();

            // Act
            var keyRing = new KeyRing(key1, new[] { key1, key2 });

            // Assert
            Assert.Equal(0, key1.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance, keyRing.DefaultAuthenticatedEncryptor);
            Assert.Equal(1, key1.NumTimesCreateEncryptorInstanceCalled);
            Assert.Same(expectedEncryptorInstance, keyRing.DefaultAuthenticatedEncryptor);
            Assert.Equal(1, key1.NumTimesCreateEncryptorInstanceCalled); // should've been cached
        }
        public void Protect_Unprotect_RoundTripsProperly()
        {
            // Arrange
            byte[] plaintext = new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50 };
            Key key = new Key(Guid.NewGuid(), DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, new AuthenticatedEncryptorConfiguration(new AuthenticatedEncryptionOptions()).CreateNewDescriptor());
            var keyRing = new KeyRing(key, new[] { key });
            var mockKeyRingProvider = new Mock<IKeyRingProvider>();
            mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing);

            var protector = new KeyRingBasedDataProtector(
                keyRingProvider: mockKeyRingProvider.Object,
                logger: null,
                originalPurposes: null,
                newPurpose: "purpose");

            // Act - protect
            byte[] protectedData = protector.Protect(plaintext);
            Assert.NotNull(protectedData);
            Assert.NotEqual(plaintext, protectedData);

            // Act - unprotect
            byte[] roundTrippedPlaintext = protector.Unprotect(protectedData);
            Assert.Equal(plaintext, roundTrippedPlaintext);
        }
        public void Unprotect_IsNotDefaultKey_Success_RequiresMigration()
        {
            // Arrange
            Guid defaultKeyId = new Guid("ba73c9ce-d322-4e45-af90-341307e11c38");
            Guid embeddedKeyId = new Guid("9b5d2db3-299f-4eac-89e9-e9067a5c1853");
            byte[] expectedCiphertext = new byte[] { 0x03, 0x05, 0x07, 0x11, 0x13, 0x17, 0x19 };
            byte[] protectedData = BuildProtectedDataFromCiphertext(embeddedKeyId, expectedCiphertext);
            byte[] expectedAad = BuildAadFromPurposeStrings(embeddedKeyId, "purpose");
            byte[] expectedPlaintext = new byte[] { 0x23, 0x29, 0x31, 0x37 };

            var mockEncryptor = new Mock<IAuthenticatedEncryptor>();
            mockEncryptor
                .Setup(o => o.Decrypt(It.IsAny<ArraySegment<byte>>(), It.IsAny<ArraySegment<byte>>()))
                .Returns<ArraySegment<byte>, ArraySegment<byte>>((actualCiphertext, actualAad) =>
                {
                    Assert.Equal(expectedCiphertext, actualCiphertext);
                    Assert.Equal(expectedAad, actualAad);
                    return expectedPlaintext;
                });
            var mockDescriptor = new Mock<IAuthenticatedEncryptorDescriptor>();
            mockDescriptor.Setup(o => o.CreateEncryptorInstance()).Returns(mockEncryptor.Object);

            Key defaultKey = new Key(defaultKeyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, new Mock<IAuthenticatedEncryptorDescriptor>().Object);
            Key embeddedKey = new Key(embeddedKeyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object);
            var keyRing = new KeyRing(defaultKey, new[] { defaultKey, embeddedKey });
            var mockKeyRingProvider = new Mock<IKeyRingProvider>();
            mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing);

            IDataProtector protector = new KeyRingBasedDataProtector(
                keyRingProvider: mockKeyRingProvider.Object,
                logger: null,
                originalPurposes: null,
                newPurpose: "purpose");

            // Act & assert - IDataProtector
            byte[] retVal = protector.Unprotect(protectedData);
            Assert.Equal(expectedPlaintext, retVal);

            // Act & assert - IPersistedDataProtector
            bool requiresMigration, wasRevoked;
            retVal = ((IPersistedDataProtector)protector).DangerousUnprotect(protectedData,
                ignoreRevocationErrors: false,
                requiresMigration: out requiresMigration,
                wasRevoked: out wasRevoked);
            Assert.Equal(expectedPlaintext, retVal);
            Assert.True(requiresMigration);
            Assert.False(wasRevoked);
        }
        public void Unprotect_KeyRevoked_RevocationDisallowed_ThrowsKeyRevoked()
        {
            // Arrange
            Guid keyId = new Guid("654057ab-2491-4471-a72a-b3b114afda38");
            byte[] protectedData = BuildProtectedDataFromCiphertext(
                keyId: keyId,
                ciphertext: new byte[0]);

            var mockDescriptor = new Mock<IAuthenticatedEncryptorDescriptor>();
            mockDescriptor.Setup(o => o.CreateEncryptorInstance()).Returns(new Mock<IAuthenticatedEncryptor>().Object);

            // the keyring has only one key
            Key key = new Key(keyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object);
            key.SetRevoked();
            var keyRing = new KeyRing(key, new[] { key });
            var mockKeyRingProvider = new Mock<IKeyRingProvider>();
            mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing);

            IDataProtector protector = new KeyRingBasedDataProtector(
                keyRingProvider: mockKeyRingProvider.Object,
                logger: null,
                originalPurposes: null,
                newPurpose: "purpose");

            // Act & assert
            var ex = ExceptionAssert2.ThrowsCryptographicException(() => protector.Unprotect(protectedData));
            Assert.Equal(Error.Common_KeyRevoked(keyId).Message, ex.Message);
        }