Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Latest Develop Branch that Includes Detailed Examples for Multiple Extensions #28

Merged
merged 37 commits into from
Apr 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
245e782
Merge branch 'master' into develop
hf-kklein Mar 17, 2020
7c326e3
remove files
hf-kklein Mar 17, 2020
aab752c
Revert "remove intermediate doc trigger (as docs are actually built h…
hf-kklein Mar 17, 2020
48f01b9
remove build process irtself
hf-kklein Mar 17, 2020
36b5e77
remove unused files
hf-kklein Mar 17, 2020
2668654
trigger docs only on master commit
hf-kklein Mar 17, 2020
0b5e03b
Merge branch 'master' into develop
hf-kklein Mar 17, 2020
d0dadaf
Merge branch 'master' into develop
hf-kklein Mar 17, 2020
93d1a38
add JSON.net schemas to repository
hf-kklein Mar 18, 2020
00b6837
add link to official json.net schema docs
hf-kklein Mar 18, 2020
714bd68
catch license exception
hf-kklein Mar 18, 2020
1828ad6
check if userProperties are null
JoschaMetze Mar 19, 2020
ff0c219
Auto stash before merge of "develop" and "origin/develop" (#26)
hamidd30 Mar 26, 2020
3ad0ce8
fix outdated exception testing
hf-kklein Mar 26, 2020
6c2fc10
Merge remote-tracking branch 'origin/develop' into develop
hf-kklein Mar 26, 2020
8cb6d74
move stuff out of obsolete class
hf-kklein Mar 26, 2020
4780de7
modularize more stuff originally from deprecated BoMapper class
hf-kklein Mar 27, 2020
7a54650
Version 0.2.0: All public components now use Properties instead of fi…
hf-kklein Mar 27, 2020
1bda252
add all json schema and protobuf files as content files to solution
hf-kklein Apr 6, 2020
1eb2135
fix wrong pathes
hf-kklein Apr 6, 2020
61876b5
generate all the puml files
hf-kklein Apr 6, 2020
d10ee28
move json-schema files out of solution again
hf-kklein Apr 6, 2020
1505a0d
fix broken link
hf-kklein Apr 6, 2020
557e845
Explain usage of proto files
hf-kklein Apr 6, 2020
88579f8
remove fixed version in csproj, otherwise it will not generate suffix
JoschaMetze Apr 6, 2020
43ff5d6
but should have bumped the prefix in the same commit
JoschaMetze Apr 6, 2020
1f519ef
Anrede should be upper case in GP
JoschaMetze Apr 6, 2020
c0f9190
Zwischenstand GRPC (was ein Mist ;))
JoschaMetze Apr 6, 2020
542006c
add showcase tests for github
hf-kklein Apr 9, 2020
dd18998
Update README.md
hf-kklein Apr 9, 2020
89d5b72
Merge remote-tracking branch 'origin/develop' into develop
hf-kklein Apr 9, 2020
57a704c
add coverlet nuget to all test projects
hf-kklein Apr 9, 2020
929c4c3
Update README.md
hf-kklein Apr 9, 2020
5f2d397
add a lot of show case tests
hf-kklein Apr 10, 2020
205ed3b
Add showcase for anonymizign
hf-kklein Apr 10, 2020
6b06918
fix broken links
hf-kklein Apr 10, 2020
718615b
Mannheim -> Grünwald
hf-kklein Apr 10, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ BO4E-dotnet.Reporting/obj
BO4E-dotnet/obj/

BO4ETestProject/bin/
BO4ETestProject/TestResults/
BO4E-dotnet/bin/

*.manifest
Expand All @@ -35,5 +36,8 @@ TestBO4E-dotnet-Reporting/obj/


TestBO4E-dotnet-Encryption/bin
TestBO4E-dotnet-Encryption/TestResults
TestBO4E-dotnet-Extensions/bin
TestBO4E-dotnet-Extensions/TestResults
TestBO4E-dotnet-Reporting/bin
TestBO4E-dotnet-Reporting/TestResults/
82 changes: 45 additions & 37 deletions BO4E-dotnet.Encryption/Anonymizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;

using BO4E.BO;
using BO4E.Extensions.BusinessObjects;
using BO4E.meta;
using BO4E.meta.LenientConverters;

using Microsoft.CSharp.RuntimeBinder;
using Microsoft.Extensions.Logging;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using Org.BouncyCastle.Crypto;

namespace BO4E.Extensions.Encryption
Expand Down Expand Up @@ -116,10 +121,13 @@ public T ApplyOperations<T>(BusinessObject bo)
foreach (DataCategory dataCategory in mapping.Keys)
{
AnonymizerApproach approach = mapping[dataCategory];
FieldInfo[] affectedFields = BoMapper.GetAnnotatedFields(bo.GetType());
foreach (FieldInfo affectedField in affectedFields)
PropertyInfo[] affectedProps = bo.GetType().GetProperties()
.Where(p => p.GetCustomAttributes(typeof(DataCategoryAttribute), false).Length > 0)
.OrderBy(ap => ap.GetCustomAttribute<JsonPropertyAttribute>()?.Order)
.ToArray<PropertyInfo>();
foreach (PropertyInfo affectedProp in affectedProps)
{
if (!affectedField.IsAnonymizerRelevant(approach, dataCategory))
if (!affectedProp.IsAnonymizerRelevant(approach, dataCategory))
{
continue;
}
Expand All @@ -128,9 +136,9 @@ public T ApplyOperations<T>(BusinessObject bo)
case AnonymizerApproach.HASH:
try
{
object affectedFieldValue = affectedField.GetValue(result);
object affectedFieldValue = affectedProp.GetValue(result);
HashObject(ref affectedFieldValue, dataCategory);
affectedField.SetValue(result, affectedFieldValue);
affectedProp.SetValue(result, affectedFieldValue);
}
catch (RuntimeBinderException e)
{
Expand All @@ -144,26 +152,26 @@ public T ApplyOperations<T>(BusinessObject bo)
* annotated default value, otherwise we can safely set null. */
bool isRequired = false;
Attribute defaultValueAttribute = null;
Attribute jsonPropertyAttribute = affectedField.GetCustomAttributes().Where(a => a.GetType() == typeof(JsonPropertyAttribute)).FirstOrDefault();
Attribute jsonPropertyAttribute = affectedProp.GetCustomAttributes().Where(a => a.GetType() == typeof(JsonPropertyAttribute)).FirstOrDefault();
if (jsonPropertyAttribute != null)
{
JsonPropertyAttribute jpa = (JsonPropertyAttribute)jsonPropertyAttribute;
if (jpa.Required == Required.Always)
{
isRequired = true;
defaultValueAttribute = affectedField.GetCustomAttributes().Where(a => a.GetType() == typeof(DefaultValueAttribute)).FirstOrDefault();
defaultValueAttribute = affectedProp.GetCustomAttributes().Where(a => a.GetType() == typeof(DefaultValueAttribute)).FirstOrDefault();
}
}

if (isRequired && defaultValueAttribute != null)
{
DefaultValueAttribute dva = (DefaultValueAttribute)defaultValueAttribute;
affectedField.SetValue(result, dva.Value);
affectedProp.SetValue(result, dva.Value);
}
else if (bo.GetType().IsSubclassOf(typeof(BO4E.BO.BusinessObject)))
{
// e.g. 1*Energiemenge (mappedObject)---> n*Verbrauch (boSubObject)
var boSubObject = affectedField.GetValue(bo);
var boSubObject = affectedProp.GetValue(bo);
if (boSubObject != null)
{
try
Expand All @@ -184,13 +192,13 @@ public T ApplyOperations<T>(BusinessObject bo)
{
_logger.LogError($"Couldn't null BO field!: {e.Message}");
}
affectedField.SetValue(result, boSubObject);
affectedProp.SetValue(result, boSubObject);
}
}
else
{
// strings, integers, elementary
affectedField.SetValue(result, null);
affectedProp.SetValue(result, null);
}
break;
case AnonymizerApproach.ENCRYPT:
Expand All @@ -200,17 +208,17 @@ public T ApplyOperations<T>(BusinessObject bo)
}
using (X509AsymmetricEncrypter xasyncenc = new X509AsymmetricEncrypter(this.publicKeyX509))
{
if (affectedField.GetValue(bo).GetType() == typeof(string))
if (affectedProp.GetValue(bo).GetType() == typeof(string))
{
if (affectedField.GetValue(bo) != null)
if (affectedProp.GetValue(bo) != null)
{
affectedField.SetValue(result, xasyncenc.Encrypt(affectedField.GetValue(bo).ToString()));
affectedProp.SetValue(result, xasyncenc.Encrypt(affectedProp.GetValue(bo).ToString()));
}
}
else if (affectedField.GetValue(bo).GetType().IsSubclassOf(typeof(BO4E.COM.COM)))
else if (affectedProp.GetValue(bo).GetType().IsSubclassOf(typeof(BO4E.COM.COM)))
{
var comObject = affectedField.GetValue(bo);
dynamic comFields = comObject.GetType().GetFields();
var comObject = affectedProp.GetValue(bo);
dynamic comFields = comObject.GetType().GetProperties();
foreach (dynamic comField in comFields)
{
try
Expand All @@ -228,21 +236,21 @@ public T ApplyOperations<T>(BusinessObject bo)
_logger.LogError($"Couldn't encrypt COM field!: {f.Message}");
}
}
affectedField.SetValue(result, comObject);
affectedProp.SetValue(result, comObject);
}
else if (affectedField.FieldType.IsSubclassOf(typeof(BO4E.BO.BusinessObject)))
else if (affectedProp.PropertyType.IsSubclassOf(typeof(BO4E.BO.BusinessObject)))
{
affectedField.SetValue(result, xasyncenc.Encrypt((BusinessObject)affectedField.GetValue(bo)));
affectedProp.SetValue(result, xasyncenc.Encrypt((BusinessObject)affectedProp.GetValue(bo)));
}
else if (affectedField.FieldType.ToString().StartsWith("BO4E.ENUM")) // todo: check for namespace instead of strinyfied comparison
else if (affectedProp.PropertyType.ToString().StartsWith("BO4E.ENUM")) // todo: check for namespace instead of strinyfied comparison
{
//affectedField.SetValue(mappedObject, Sha256HashEnum(affectedField.GetValue(mappedObject).ToString()));
_logger.LogWarning($"Encrypting {affectedField.FieldType} is not supported, since the result would not be a valid ENUM value.");
_logger.LogWarning($"Encrypting {affectedProp.PropertyType} is not supported, since the result would not be a valid ENUM value.");
//throw new NotSupportedException($"Hashing {affectedField.FieldType} is not supported, since the result would not be a valid ENUM value.");
}
else
{
throw new NotImplementedException($"Encrypting {affectedField.FieldType} is not implemented yet.");
throw new NotImplementedException($"Encrypting {affectedProp.PropertyType} is not implemented yet.");
}
}
break;
Expand All @@ -253,7 +261,7 @@ public T ApplyOperations<T>(BusinessObject bo)
}
using (X509AsymmetricEncrypter xasydec = new X509AsymmetricEncrypter(this.privateKey))
{
affectedField.SetValue(result, xasydec.Decrypt(affectedField.GetValue(bo).ToString()));
affectedProp.SetValue(result, xasydec.Decrypt(affectedProp.GetValue(bo).ToString()));
}
continue;
case AnonymizerApproach.KEEP:
Expand Down Expand Up @@ -336,25 +344,25 @@ protected void HashObject(ref object input, DataCategory? dataCategory = null)
}
else
{
var fields = inputType.GetFields();
foreach (var field in fields)
var properties = inputType.GetProperties();
foreach (var prop in properties)
{
if (field.GetValue(input) == null || !field.IsHashingRelevant(dataCategory))
if (prop.GetValue(input) == null || !prop.IsHashingRelevant(dataCategory))
{
continue;
}
try
{
object o = field.GetValue(input);
object o = prop.GetValue(input);
HashObject(ref o, dataCategory);
field.SetValue(input, o);
prop.SetValue(input, o);
}
catch (Exception f)
{
throw new ArgumentException($"Couldn't hash field {field.Name}: {f.Message}");
throw new ArgumentException($"Couldn't hash field {prop.Name}: {f.Message}");
}
}
if (fields.Count() == 0)
if (properties.Count() == 0)
{
throw new NotImplementedException($"Type {inputType} with value '{input}' has no subfields but is not handled separately.");
}
Expand Down Expand Up @@ -415,28 +423,28 @@ protected void HashString(ref string input, DataCategory? dataCategory)
/// <returns>true if the <see cref="Marktlokation.marktlokationsId"/> fulfills the requirements of a hashed key</returns>
public static bool HasHashedKey(Marktlokation ma)
{
return !string.IsNullOrWhiteSpace(ma.marktlokationsId) && ma.marktlokationsId.StartsWith(HASHED_MARKTLOKATION_PREFIX);
return !string.IsNullOrWhiteSpace(ma.MarktlokationsId) && ma.MarktlokationsId.StartsWith(HASHED_MARKTLOKATION_PREFIX);
}
/// <summary>
/// check if a Messlokation has been pseudonymized using <see cref="AnonymizerApproach.HASH"/>
/// As of 2019 it's impossible for a "real" Messlokation to fulfill this condition.
/// </summary>
/// <param name="me">Messlokation</param>
/// <returns>true if the <see cref="Messlokation.messlokationsId"/> fulfills the requirements of a hashed key</returns>
/// <returns>true if the <see cref="Messlokation.MesslokationsId"/> fulfills the requirements of a hashed key</returns>
public static bool HasHashedKey(Messlokation me)
{
return !string.IsNullOrWhiteSpace(me.messlokationsId) && me.messlokationsId.StartsWith(HASHED_MESSLOKATION_PREFIX);
return !string.IsNullOrWhiteSpace(me.MesslokationsId) && me.MesslokationsId.StartsWith(HASHED_MESSLOKATION_PREFIX);
}

/// <summary>
/// check if an Energiemenge been pseudonymized using <see cref="AnonymizerApproach.HASH"/>.
/// Calls <see cref="IsHashedKey(string)"/> for <see cref="Energiemenge.lokationsId"/>.
/// Calls <see cref="IsHashedKey(string)"/> for <see cref="Energiemenge.LokationsId"/>.
/// </summary>
/// <param name="em">Energiemenge</param>
/// <returns>true if the <see cref="Energiemenge.lokationsId"/> fulfills the requirements of a hashed key</returns>
/// <returns>true if the <see cref="Energiemenge.LokationsId"/> fulfills the requirements of a hashed key</returns>
public static bool HasHashedKey(Energiemenge em)
{
return IsHashedKey(em.lokationsId);
return IsHashedKey(em.LokationsId);
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion BO4E-dotnet.Encryption/AnonymizerConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class AnonymizerConfiguration
public Dictionary<DataCategory, AnonymizerApproach> operations { get; private set; }

/// <summary>
/// set of key in <see cref="BO4E.BO.BusinessObject.userProperties"/> / <see cref="BO4E.COM.COM.userProperties"/> that should not be affected by the anonymizing operations
/// set of key in <see cref="BO4E.BO.BusinessObject.UserProperties"/> / <see cref="BO4E.COM.COM.UserProperties"/> that should not be affected by the anonymizing operations
/// </summary>
[JsonProperty(Required = Required.Default)]
public HashSet<string> unaffectedUserProperties;
Expand Down
23 changes: 19 additions & 4 deletions BO4E-dotnet.Encryption/AsymmetricEncrypter.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Text;

using BO4E.BO;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using Sodium;

namespace BO4E.Extensions.Encryption
Expand All @@ -19,8 +21,10 @@ public class AsymmetricEncrypter : Encrypter
/// <param name="publicKey">public key</param>
public AsymmetricEncrypter(byte[] privateKey, byte[] publicKey)
{
this.privateKey = privateKey;
this.ownPublicKey = publicKey;
this.ownPublicKey = new byte[publicKey.Length];
this.privateKey = new byte[privateKey.Length];
privateKey.CopyTo(this.privateKey, 0);
publicKey.CopyTo(this.ownPublicKey, 0);
}
/// <summary>
/// Instantiate with private and public key
Expand Down Expand Up @@ -105,10 +109,21 @@ public override BusinessObject Decrypt(EncryptedObject encryptedObject)
{
return null;
}
string plainString = Decrypt(eo.cipherText, eo.publicKey, eo.nonce);
string plainString = Decrypt(eo.CipherText, eo.PublicKey, eo.Nonce);
return JsonConvert.DeserializeObject<BusinessObject>(plainString);
}

public override T Decrypt<T>(EncryptedObject encryptedObject)
{
EncryptedObjectPublicKeyBox eo = (EncryptedObjectPublicKeyBox)(encryptedObject);// (EncryptedObjectPublicKeyBox)BoMapper.MapObject("EncryptedObjectPublicKeyBox", JObject.FromObject(encryptedObject));
if (eo == null)
{
return (T)null;
}
string plainString = Decrypt(eo.CipherText, eo.PublicKey, eo.Nonce);
return JsonConvert.DeserializeObject<T>(plainString);
}

public override void Dispose()
{
if (privateKey != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<PackageId>Hochfrequenz.BO4E.Extensions.Encryption</PackageId>
<Authors />
<Company>Hochfrequenz Unternehmensberatung GmbH</Company>
<Version>0.2.0</Version>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
Expand Down
12 changes: 6 additions & 6 deletions BO4E-dotnet.Encryption/EncryptedObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ public abstract class EncryptedObject : BusinessObject
/// <summary>
/// encryption scheme used
/// </summary>
[JsonProperty(Required = Required.Always, Order = 7)]
[JsonProperty(PropertyName = "encryptionScheme", Required = Required.Always, Order = 7)]
[BoKey]
public EncryptionScheme encryptionScheme;
public EncryptionScheme EncryptionScheme { get; set; }

/// <summary>
/// base64 encoded cipher text of the original objects JSON serialisation
/// </summary>
[JsonProperty(Required = Required.Always, Order = 8)]
[JsonProperty(PropertyName = "cipherText", Required = Required.Always, Order = 8)]
[BoKey]
public string cipherText;
public string CipherText { get; set; }

/// <summary>
/// create a new EncryptedObject instance by providing both
Expand All @@ -35,8 +35,8 @@ public abstract class EncryptedObject : BusinessObject
/// <param name="es">the encryption scheme</param>
public EncryptedObject(string _cipherText, EncryptionScheme es) : base()
{
this.cipherText = _cipherText;
this.encryptionScheme = es;
this.CipherText = _cipherText;
this.EncryptionScheme = es;
}
}
}
13 changes: 7 additions & 6 deletions BO4E-dotnet.Encryption/EncryptedObjectAEAD.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using BO4E.ENUM;

using Newtonsoft.Json;

namespace BO4E.BO
Expand All @@ -13,20 +14,20 @@ public class EncryptedObjectAEAD : EncryptedObject
/// <param name="nonce">unique nonce / initialisation vector (base 64 encoded, must not be used twice)</param>
public EncryptedObjectAEAD(string cipherText, string associatedData, string nonce) : base(cipherText, EncryptionScheme.SodiumSymmetricAEAD)
{
this.associatedData = associatedData;
this.nonce = nonce;
this.AssociatedData = associatedData;
this.Nonce = nonce;
}

/// <summary>
/// base64 encoded unique nonce / initialisation vector
/// </summary>
[JsonProperty(Required = Required.Always, Order = 8)]
public string nonce;
[JsonProperty(PropertyName = "nonce", Required = Required.Always, Order = 8)]
public string Nonce { get; set; }

/// <summary>
/// associated data string (UTF-8); might be an empty string but not null
/// </summary>
[JsonProperty(Required = Required.Always, Order = 5)]
public string associatedData;
[JsonProperty(PropertyName = "AssociatedData", Required = Required.Always, Order = 5)]
public string AssociatedData { get; set; }
}
}
Loading