Initial version.

This commit is contained in:
Oliver Hauff 2021-05-13 17:07:16 +02:00
commit 6bab491a21
40 changed files with 1812 additions and 0 deletions

View file

@ -0,0 +1,82 @@
using Serilog;
using TINK.Model.Device;
namespace TINK.Services.BluetoothLock.Crypto
{
public class AuthCryptoHelper
{
private ICipher Cipher { get; }
/// <summary> Encrypted seed (random number) created inside ILOCKIT and passd to app.</summary>
private byte[] SeedLockEncrypted { get; }
/// <summary> Contstructs a auth crypto helper object.</summary>
/// <param name="seedLockEncrypted">Encrypted seed to deocode using <see cref="KeyCopri"/>.</param>
/// <param name="keyCopri">Key used to to decrypt <see cref="SeedLockEncrypted"/>.</param>
public AuthCryptoHelper(
byte[] seedLockEncrypted,
byte[] keyCopri,
ICipher cipher)
{
KeyCopri = keyCopri;
SeedLockEncrypted = seedLockEncrypted;
Cipher = cipher ?? new Cipher();
}
/// <summary> Public for testing purposes only.</summary>
public byte[] GetSeedLock()
{
byte[] seedLockDecrypted;
var seedLockEncrypted = SeedLockEncrypted;
var keyCopri = KeyCopri;
try
{
seedLockDecrypted = Cipher.Decrypt(
keyCopri,
seedLockEncrypted);
}
catch (System.Exception exception)
{
Log.ForContext<AuthCryptoHelper>().Error("Decrypting seed from lock failed. {Exception}", exception);
throw;
}
Log.ForContext<AuthCryptoHelper>().Verbose($"Lock random number decrypted from {string.Join(",", seedLockEncrypted)} to {string.Join(",", seedLockDecrypted)} using {string.Join(", ", keyCopri)}.");
return seedLockDecrypted;
}
public byte[] GetAccessKeyEncrypted()
{
var accessKey = GetSeedLock();
if (accessKey == null || accessKey.Length <= 0)
{
Log.ForContext<AuthCryptoHelper>().Error("Creating access key failed, Key must not be null or empty.");
throw new System.Exception();
}
accessKey[accessKey.Length - 1] += 1;
var keyCopri = KeyCopri;
byte[] acccessKeyEncrypted;
try
{
acccessKeyEncrypted = Cipher.Encrypt(
keyCopri,
accessKey);
}
catch (System.Exception exception)
{
Log.ForContext<AuthCryptoHelper>().Error("Encrypting access key failed. {Exception}", exception);
throw;
}
Log.ForContext<AuthCryptoHelper>().Verbose($"Access key encrypted from {string.Join(",", accessKey)} to {string.Join(",", acccessKeyEncrypted)} using {string.Join(", ", keyCopri)}.");
return acccessKeyEncrypted;
}
public byte[] KeyCopri { get; }
}
}

View file

@ -0,0 +1,88 @@
using System;
using System.IO;
using System.Security.Cryptography;
using TINK.Model.Device;
namespace TINK.Services.BluetoothLock.Crypto
{
public class Cipher : ICipher
{
/// <summary> Decrypt data. </summary>
/// <remarks>
/// Further info see:
/// https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=netcore-3.1 for further info
// https://docs.microsoft.com/en-us/dotnet/standard/security/cryptographic-services
// https://stackoverflow.com/questions/24903575/how-to-return-byte-when-decrypt-using-cryptostream-descryptoserviceprovider/24903689
/// </remarks>
/// <param name="key">Key to decrypt data with.</param>
/// <param name="encrypted">Encrpyted data to decrypt.</param>
/// <returns>Decrypted data.</returns>
public byte[] Decrypt(byte[] key, byte[] encrypted)
{
// Check arguments.
if (encrypted == null || encrypted.Length <= 0)
throw new ArgumentNullException(nameof(encrypted));
if (key == null || key.Length <= 0)
throw new ArgumentNullException(nameof(key));
using (Aes aesAlg = Aes.Create())
{
aesAlg.KeySize = 192;
aesAlg.Mode = CipherMode.ECB;
aesAlg.Padding = PaddingMode.None;
aesAlg.Key = key;
// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (var msDecrypt = new MemoryStream())
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
{
csDecrypt.Write(encrypted, 0, encrypted.Length);
csDecrypt.FlushFinalBlock();
return msDecrypt.ToArray();
}
}
}
}
public byte[] Encrypt(byte[] key, byte[] clear)
{
// Check arguments.
if (clear == null || clear.Length <= 0)
throw new ArgumentNullException("plainText");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("Key");
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
aesAlg.KeySize = 192;
aesAlg.Mode = CipherMode.ECB;
aesAlg.Padding = PaddingMode.None;
aesAlg.Key = key;
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(clear, 0, clear.Length);
csEncrypt.FlushFinalBlock();
return msEncrypt.ToArray();
}
}
}
}
}
}