Skip to content

Commit e9e2b1f

Browse files
DmitryLukyanovBorisDog
authored andcommitted
CSHARP-3527: Consider accepting EncryptionAlgorithm enum in EncryptOptions. (#526)
CSHARP-3527: Consider accepting EncryptionAlgorithm enum in EncryptOptions.
1 parent bd47f5d commit e9e2b1f

File tree

9 files changed

+207
-10
lines changed

9 files changed

+207
-10
lines changed

src/MongoDB.Driver.Core/MongoDB.Driver.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@
126126
<ItemGroup>
127127
<PackageReference Include="DnsClient" Version="1.4.0" />
128128
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.6.2" PrivateAssets="All" />
129-
<PackageReference Include="MongoDB.Libmongocrypt" Version="1.2.1" />
129+
<PackageReference Include="MongoDB.Libmongocrypt" Version="1.2.2" />
130130
<PackageReference Include="SharpCompress" Version="0.23.0" />
131131
<PackageReference Include="System.Buffers" Version="4.5.1" />
132132
</ItemGroup>

src/MongoDB.Driver/Encryption/ClientEncryption.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,11 @@ public void Dispose()
121121
/// <returns>The encrypted value.</returns>
122122
public BsonBinaryData Encrypt(BsonValue value, EncryptOptions encryptOptions, CancellationToken cancellationToken)
123123
{
124-
var algorithm = (EncryptionAlgorithm)Enum.Parse(typeof(EncryptionAlgorithm), encryptOptions.Algorithm);
125124
return _libMongoCryptController.EncryptField(
126125
value,
127126
encryptOptions.KeyId,
128127
encryptOptions.AlternateKeyName,
129-
algorithm,
128+
encryptOptions.Algorithm,
130129
cancellationToken);
131130
}
132131

@@ -139,12 +138,11 @@ public BsonBinaryData Encrypt(BsonValue value, EncryptOptions encryptOptions, Ca
139138
/// <returns>The encrypted value.</returns>
140139
public Task<BsonBinaryData> EncryptAsync(BsonValue value, EncryptOptions encryptOptions, CancellationToken cancellationToken)
141140
{
142-
var algorithm = (EncryptionAlgorithm)Enum.Parse(typeof(EncryptionAlgorithm), encryptOptions.Algorithm);
143141
return _libMongoCryptController.EncryptFieldAsync(
144142
value,
145143
encryptOptions.KeyId,
146144
encryptOptions.AlternateKeyName,
147-
algorithm,
145+
encryptOptions.Algorithm,
148146
cancellationToken);
149147
}
150148
}

src/MongoDB.Driver/Encryption/EncryptOptions.cs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ namespace MongoDB.Driver.Encryption
2323
/// </summary>
2424
public class EncryptOptions
2525
{
26+
#region static
27+
private static string ConvertEnumAlgorithmToString(EncryptionAlgorithm encryptionAlgorithm) =>
28+
encryptionAlgorithm switch
29+
{
30+
EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic => "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
31+
EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random => "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
32+
_ => encryptionAlgorithm.ToString(),
33+
};
34+
#endregion
35+
2636
// private fields
2737
private readonly string _algorithm;
2838
private readonly string _alternateKeyName;
@@ -40,12 +50,38 @@ public EncryptOptions(
4050
Optional<string> alternateKeyName = default,
4151
Optional<Guid?> keyId = default)
4252
{
43-
_algorithm = Ensure.IsNotNull(algorithm, nameof(algorithm));
53+
Ensure.IsNotNull(algorithm, nameof(algorithm));
54+
if (Enum.TryParse<EncryptionAlgorithm>(algorithm, out var @enum))
55+
{
56+
_algorithm = ConvertEnumAlgorithmToString(@enum);
57+
}
58+
else
59+
{
60+
_algorithm = algorithm;
61+
}
62+
4463
_alternateKeyName = alternateKeyName.WithDefault(null);
4564
_keyId = keyId.WithDefault(null);
4665
EnsureThatOptionsAreValid();
4766
}
4867

68+
/// <summary>
69+
/// Initializes a new instance of the <see cref="EncryptOptions"/> class.
70+
/// </summary>
71+
/// <param name="algorithm">The encryption algorithm.</param>
72+
/// <param name="alternateKeyName">The alternate key name.</param>
73+
/// <param name="keyId">The key Id.</param>
74+
public EncryptOptions(
75+
EncryptionAlgorithm algorithm,
76+
Optional<string> alternateKeyName = default,
77+
Optional<Guid?> keyId = default)
78+
: this(
79+
algorithm: ConvertEnumAlgorithmToString(algorithm),
80+
alternateKeyName,
81+
keyId)
82+
{
83+
}
84+
4985
// public properties
5086
/// <summary>
5187
/// Gets the algorithm.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* Copyright 2021-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
namespace MongoDB.Driver.Encryption
17+
{
18+
/// <summary>
19+
/// Represents an encryption algorithm.
20+
/// </summary>
21+
public enum EncryptionAlgorithm
22+
{
23+
/// <summary>
24+
/// Deterministic algorithm.
25+
/// </summary>
26+
AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic,
27+
/// <summary>
28+
/// Random algorithm.
29+
/// </summary>
30+
AEAD_AES_256_CBC_HMAC_SHA_512_Random
31+
}
32+
}

src/MongoDB.Driver/Encryption/ExplicitEncryptionLibMongoCryptController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public BsonBinaryData EncryptField(
143143
BsonValue value,
144144
Guid? keyId,
145145
string alternateKeyName,
146-
EncryptionAlgorithm encryptionAlgorithm,
146+
string encryptionAlgorithm,
147147
CancellationToken cancellationToken)
148148
{
149149
try
@@ -188,7 +188,7 @@ public async Task<BsonBinaryData> EncryptFieldAsync(
188188
BsonValue value,
189189
Guid? keyId,
190190
string alternateKeyName,
191-
EncryptionAlgorithm encryptionAlgorithm,
191+
string encryptionAlgorithm,
192192
CancellationToken cancellationToken)
193193
{
194194
try

src/MongoDB.Driver/MongoDB.Driver.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
</PropertyGroup>
5151
<ItemGroup>
5252
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.6.2" PrivateAssets="All" />
53-
<PackageReference Include="MongoDB.Libmongocrypt" Version="1.2.1" />
53+
<PackageReference Include="MongoDB.Libmongocrypt" Version="1.2.2" />
5454
</ItemGroup>
5555

5656
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.5'">

tests/MongoDB.Driver.Examples/ExplicitEncryptionExamples.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
using MongoDB.Driver.Core.Misc;
2121
using MongoDB.Driver.Core.TestHelpers.XunitExtensions;
2222
using MongoDB.Driver.Encryption;
23-
using MongoDB.Libmongocrypt;
2423
using Xunit;
2524
using Xunit.Abstractions;
2625

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/* Copyright 2021-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System;
17+
using FluentAssertions;
18+
using MongoDB.Driver.Encryption;
19+
using Xunit;
20+
21+
namespace MongoDB.Driver.Tests
22+
{
23+
public class EncryptOptionsTests
24+
{
25+
[Fact]
26+
public void Constructor_should_fail_when_algorithm_is_null()
27+
{
28+
var exception = Record.Exception(() => new EncryptOptions(algorithm: null));
29+
exception.Should().BeOfType<ArgumentNullException>();
30+
}
31+
32+
[Fact]
33+
public void Constructor_should_fail_when_keyId_and_alternateKeyName_are_both_empty()
34+
{
35+
var exception = Record.Exception(() => new EncryptOptions(algorithm: "test", alternateKeyName: null, keyId: null));
36+
var e = exception.Should().BeOfType<ArgumentException>().Subject;
37+
e.Message.Should().Be("Key Id and AlternateKeyName may not both be null.");
38+
}
39+
40+
[Fact]
41+
public void Constructor_should_fail_when_keyId_and_alternateKeyName_are_both_specified()
42+
{
43+
var exception = Record.Exception(() => new EncryptOptions(algorithm: "test", alternateKeyName: "alternateKeyName", keyId: Guid.NewGuid()));
44+
var e = exception.Should().BeOfType<ArgumentException>().Subject;
45+
e.Message.Should().Be("Key Id and AlternateKeyName may not both be set.");
46+
}
47+
48+
[Theory]
49+
[InlineData(EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic, "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")]
50+
[InlineData(EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random, "AEAD_AES_256_CBC_HMAC_SHA_512-Random")]
51+
// these values are required to be supported due a CSHARP-3527 bug of how we worked with input algorithm values. So,
52+
// since we cannot remove them because of BC, we need to keep supporting them even after solving the underlying bug
53+
[InlineData("AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")]
54+
[InlineData("AEAD_AES_256_CBC_HMAC_SHA_512_Random", "AEAD_AES_256_CBC_HMAC_SHA_512-Random")]
55+
// the below values match to the spec wording
56+
[InlineData("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")]
57+
[InlineData("AEAD_AES_256_CBC_HMAC_SHA_512-Random", "AEAD_AES_256_CBC_HMAC_SHA_512-Random")]
58+
// just a random string value
59+
[InlineData("TEST_random", "TEST_random")]
60+
// just a random value in enum form
61+
[InlineData((EncryptionAlgorithm)99, "99")]
62+
public void Constructor_should_support_different_algorithm_representations(object algorithm, string expectedAlgorithmRepresentation)
63+
{
64+
var alternateKeyName = "test";
65+
66+
EncryptOptions subject;
67+
if (algorithm is EncryptionAlgorithm enumedAlgorithm)
68+
{
69+
subject = new EncryptOptions(enumedAlgorithm, alternateKeyName: alternateKeyName);
70+
}
71+
else
72+
{
73+
subject = new EncryptOptions(algorithm.ToString(), alternateKeyName: alternateKeyName);
74+
}
75+
76+
subject.Algorithm.Should().Be(expectedAlgorithmRepresentation);
77+
subject.AlternateKeyName.Should().Be("test");
78+
subject.KeyId.Should().NotHaveValue();
79+
}
80+
81+
[Fact]
82+
public void With_should_set_correct_values()
83+
{
84+
var originalAlgorithm = "originalAlgorithm";
85+
var newAlgorithm = "newAlgorithm";
86+
var originalKeyId = Guid.Empty;
87+
var newKeyId = Guid.NewGuid();
88+
var originalAlternateKeyName = "test";
89+
var newAlternateKeyName = "new";
90+
91+
var subject = CreateConfiguredSubject(withKeyId: true);
92+
AssertValues(subject, originalAlgorithm, originalKeyId, null);
93+
94+
subject = subject.With(algorithm: newAlgorithm);
95+
AssertValues(subject, newAlgorithm, originalKeyId, null);
96+
97+
subject = subject.With(keyId: newKeyId);
98+
AssertValues(subject, newAlgorithm, newKeyId, null);
99+
100+
subject = CreateConfiguredSubject(withKeyId: false);
101+
AssertValues(subject, originalAlgorithm, null, originalAlternateKeyName);
102+
103+
subject = subject.With(alternateKeyName: newAlternateKeyName);
104+
AssertValues(subject, originalAlgorithm, null, newAlternateKeyName);
105+
106+
static void AssertValues(EncryptOptions subject, string algorithm, Guid? keyId, string alternateKeyName)
107+
{
108+
subject.Algorithm.Should().Be(algorithm);
109+
subject.KeyId.Should().Be(keyId);
110+
subject.AlternateKeyName.Should().Be(alternateKeyName);
111+
}
112+
113+
EncryptOptions CreateConfiguredSubject(bool withKeyId)
114+
{
115+
if (withKeyId)
116+
{
117+
return new EncryptOptions(algorithm: originalAlgorithm, keyId: originalKeyId);
118+
}
119+
else
120+
{
121+
return new EncryptOptions(algorithm: originalAlgorithm, alternateKeyName: originalAlternateKeyName);
122+
}
123+
}
124+
}
125+
}
126+
}

tests/MongoDB.Driver.Tests/EncryptionTests.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,12 @@ public void Mongocryptd_should_be_initialized_only_for_auto_encryption([Values(f
184184
}
185185
}
186186

187+
[Fact]
188+
public void Mongocrypt_native_library_should_have_expected_version()
189+
{
190+
Library.Version.Should().Be("1.2.1");
191+
}
192+
187193
// private methods
188194
private object CreateInstance(Type type)
189195
{

0 commit comments

Comments
 (0)