-
-
Notifications
You must be signed in to change notification settings - Fork 232
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Showing
14 changed files
with
388 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
src/Butil/Bit.Butil/Internals/JsInterops/CryptoJsInterop.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
using System.Threading.Tasks; | ||
using Microsoft.JSInterop; | ||
|
||
namespace Bit.Butil; | ||
|
||
internal static class CryptoJsInterop | ||
{ | ||
internal static ValueTask<byte[]> CryptoEncrypt<T>(this IJSRuntime js, T algorithm, byte[] key, byte[] data, CryptoKeyHash? keyHash) where T : ICryptoAlgorithmParams | ||
{ | ||
if (algorithm.GetType() == typeof(RsaOaepCryptoAlgorithmParams)) | ||
{ | ||
var keyHashString = keyHash switch | ||
{ | ||
CryptoKeyHash.Sha384 => "SHA-384", | ||
CryptoKeyHash.Sha512 => "SHA-512", | ||
_ => "SHA-256", | ||
}; | ||
|
||
return js.InvokeAsync<byte[]>("BitButil.crypto.encryptRsaOaep", algorithm, key, data, keyHashString); | ||
} | ||
|
||
if (algorithm.GetType() == typeof(AesCtrCryptoAlgorithmParams)) | ||
{ | ||
return js.InvokeAsync<byte[]>("BitButil.crypto.encryptAesCtr", algorithm, key, data); | ||
} | ||
|
||
if (algorithm.GetType() == typeof(AesCbcCryptoAlgorithmParams)) | ||
{ | ||
return js.InvokeAsync<byte[]>("BitButil.crypto.encryptAesCbc", algorithm, key, data); | ||
} | ||
|
||
|
||
return js.InvokeAsync<byte[]>("BitButil.crypto.encryptAesGcm", algorithm, key, data); | ||
} | ||
internal static ValueTask<byte[]> CryptoEncrypt(this IJSRuntime js, CryptoAlgorithm algorithm, byte[] key, byte[] data, byte[]? iv, CryptoKeyHash? keyHash) | ||
=> algorithm switch | ||
{ | ||
CryptoAlgorithm.AesCtr => CryptoEncrypt(js, new AesCtrCryptoAlgorithmParams { Counter = iv }, key, data, null), | ||
CryptoAlgorithm.AesCbc => CryptoEncrypt(js, new AesCbcCryptoAlgorithmParams { Iv = iv }, key, data, null), | ||
CryptoAlgorithm.AesGcm => CryptoEncrypt(js, new AesGcmCryptoAlgorithmParams { Iv = iv }, key, data, null), | ||
_ => CryptoEncrypt(js, new RsaOaepCryptoAlgorithmParams(), key, data, keyHash), | ||
}; | ||
|
||
internal static ValueTask<byte[]> CryptoDecrypt<T>(this IJSRuntime js, T algorithm, byte[] key, byte[] data, CryptoKeyHash? keyHash) where T : ICryptoAlgorithmParams | ||
{ | ||
if (algorithm.GetType() == typeof(RsaOaepCryptoAlgorithmParams)) | ||
{ | ||
var keyHashString = keyHash switch | ||
{ | ||
CryptoKeyHash.Sha384 => "SHA-384", | ||
CryptoKeyHash.Sha512 => "SHA-512", | ||
_ => "SHA-256", | ||
}; | ||
|
||
return js.InvokeAsync<byte[]>("BitButil.crypto.decryptRsaOaep", algorithm, key, data, keyHashString); | ||
} | ||
|
||
if (algorithm.GetType() == typeof(AesCtrCryptoAlgorithmParams)) | ||
{ | ||
return js.InvokeAsync<byte[]>("BitButil.crypto.decryptAesCtr", algorithm, key, data); | ||
} | ||
|
||
if (algorithm.GetType() == typeof(AesCbcCryptoAlgorithmParams)) | ||
{ | ||
return js.InvokeAsync<byte[]>("BitButil.crypto.decryptAesCbc", algorithm, key, data); | ||
} | ||
|
||
|
||
return js.InvokeAsync<byte[]>("BitButil.crypto.decryptAesGcm", algorithm, key, data); | ||
} | ||
internal static ValueTask<byte[]> CryptoDecrypt(this IJSRuntime js, CryptoAlgorithm algorithm, byte[] key, byte[] data, byte[]? iv, CryptoKeyHash? keyHash) | ||
=> algorithm switch | ||
{ | ||
CryptoAlgorithm.AesCtr => CryptoDecrypt(js, new AesCtrCryptoAlgorithmParams { Counter = iv }, key, data, null), | ||
CryptoAlgorithm.AesCbc => CryptoDecrypt(js, new AesCbcCryptoAlgorithmParams { Iv = iv }, key, data, null), | ||
CryptoAlgorithm.AesGcm => CryptoDecrypt(js, new AesGcmCryptoAlgorithmParams { Iv = iv }, key, data, null), | ||
_ => CryptoDecrypt(js, new RsaOaepCryptoAlgorithmParams(), key, data, keyHash), | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using System.Threading.Tasks; | ||
using Microsoft.JSInterop; | ||
|
||
namespace Bit.Butil; | ||
|
||
/// <summary> | ||
/// The Crypto interface represents basic cryptography features available in the current context. | ||
/// It allows access to a cryptographically strong random number generator and to cryptographic primitives. | ||
/// <br /> | ||
/// More info: <see href="https://developer.mozilla.org/en-US/docs/Web/API/Crypto">https://developer.mozilla.org/en-US/docs/Web/API/Crypto</see> | ||
/// </summary> | ||
public class Crypto(IJSRuntime js) | ||
{ | ||
/// <summary> | ||
/// The Encrypt method of the Crypto interface that encrypts data. | ||
/// <br /> | ||
/// <see href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt">https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt</see> | ||
/// </summary> | ||
public ValueTask<byte[]> Encrypt<T>(T algorithm, byte[] key, byte[] data, CryptoKeyHash? keyHash = null) where T : ICryptoAlgorithmParams | ||
=> js.CryptoEncrypt(algorithm, key, data, keyHash); | ||
/// <summary> | ||
/// The Encrypt method of the Crypto interface that encrypts data. | ||
/// <br /> | ||
/// <see href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt">https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt</see> | ||
/// </summary> | ||
public ValueTask<byte[]> Encrypt(CryptoAlgorithm algorithm, byte[]key, byte[]data, byte[]? iv = null, CryptoKeyHash? keyHash = null) | ||
=> js.CryptoEncrypt(algorithm, key, data, iv, keyHash); | ||
|
||
/// <summary> | ||
/// The Decrypt method of the Crypto interface that decrypts data. | ||
/// <br /> | ||
/// <see href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt">https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt</see> | ||
/// </summary> | ||
public ValueTask<byte[]> Decrypt<T>(T algorithm, byte[] key, byte[] data, CryptoKeyHash? keyHash = null) where T : ICryptoAlgorithmParams | ||
=> js.CryptoDecrypt(algorithm, key, data, keyHash); | ||
/// <summary> | ||
/// The Decrypt method of the Crypto interface that decrypts data. | ||
/// <br /> | ||
/// <see href="https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt">https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt</see> | ||
/// </summary> | ||
public ValueTask<byte[]> Decrypt(CryptoAlgorithm algorithm, byte[] key, byte[] data, byte[]? iv = null, CryptoKeyHash? keyHash = null) | ||
=> js.CryptoDecrypt(algorithm, key, data, iv, keyHash); | ||
} |
16 changes: 16 additions & 0 deletions
16
src/Butil/Bit.Butil/Publics/Crypto/AesCbcCryptoAlgorithmParams.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
namespace Bit.Butil; | ||
|
||
/// <summary> | ||
/// Represents the object that should be passed as the algorithm parameter into Crypto APIs when using the AES-CBC algorithm. | ||
/// <br/> | ||
/// <see href="https://developer.mozilla.org/en-US/docs/Web/API/AesCbcParams">https://developer.mozilla.org/en-US/docs/Web/API/AesCbcParams</see> | ||
/// </summary> | ||
public class AesCbcCryptoAlgorithmParams : ICryptoAlgorithmParams | ||
{ | ||
public string Name => "AES-CBC"; | ||
|
||
/// <summary> | ||
/// The initialization vector. Must be 16 bytes (128 bits), unpredictable, and preferably cryptographically random. | ||
/// </summary> | ||
public byte[] Iv { get; set; } = default!; | ||
} |
21 changes: 21 additions & 0 deletions
21
src/Butil/Bit.Butil/Publics/Crypto/AesCtrCryptoAlgorithmParams.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
namespace Bit.Butil; | ||
|
||
/// <summary> | ||
/// Represents the object that should be passed as the algorithm parameter into Crypto APIs when using the AES-CTR algorithm. | ||
/// <br/> | ||
/// <see href="https://developer.mozilla.org/en-US/docs/Web/API/AesCtrParams">https://developer.mozilla.org/en-US/docs/Web/API/AesCtrParams</see> | ||
/// </summary> | ||
public class AesCtrCryptoAlgorithmParams : ICryptoAlgorithmParams | ||
{ | ||
public string Name => "AES-CTR"; | ||
|
||
/// <summary> | ||
/// The initial value of the counter block. This must be 16 bytes (128 bits) long (the AES block size). | ||
/// </summary> | ||
public byte[] Counter { get; set; } = default!; | ||
|
||
/// <summary> | ||
/// The number of bits in the counter block that are used for the actual counter. | ||
/// </summary> | ||
public int Length { get; set; } | ||
} |
30 changes: 30 additions & 0 deletions
30
src/Butil/Bit.Butil/Publics/Crypto/AesGcmCryptoAlgorithmParams.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
namespace Bit.Butil; | ||
|
||
/// <summary> | ||
/// Represents the object that should be passed as the algorithm parameter into Crypto APIs when using the AES-GCM algorithm. | ||
/// <br/> | ||
/// <see href="https://developer.mozilla.org/en-US/docs/Web/API/AesCbcParams">https://developer.mozilla.org/en-US/docs/Web/API/AesCbcParams</see> | ||
/// </summary> | ||
public class AesGcmCryptoAlgorithmParams : ICryptoAlgorithmParams | ||
{ | ||
public string Name => "AES-GCM"; | ||
|
||
/// <summary> | ||
/// The initialization vector. This must be unique for every encryption operation carried out with a given key. | ||
/// Put another way: never reuse an IV with the same key. | ||
/// The AES-GCM specification recommends that the IV should be 96 bits long, | ||
/// and typically contains bits from a random number generator. | ||
/// </summary> | ||
public byte[] Iv { get; set; } = default!; | ||
|
||
/// <summary> | ||
/// This contains additional data that will not be encrypted but will be authenticated along with the encrypted data. | ||
/// </summary> | ||
public byte[] AdditionalData { get; set; } = default!; | ||
|
||
/// <summary> | ||
/// This determines the size in bits of the authentication tag generated in the encryption operation and | ||
/// used for authentication in the corresponding decryption. | ||
/// </summary> | ||
public AesGcmTagLength TagLength { get; set; } = AesGcmTagLength.Sixteen; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
namespace Bit.Butil; | ||
|
||
/// <summary> | ||
/// The recommended tagLength number values in Bytes with the corresponding bits value. | ||
/// </summary> | ||
public enum AesGcmTagLength | ||
{ | ||
Four = 32, | ||
Eight = 64, | ||
Twelve = 96, | ||
Thirteen = 104, | ||
Fourteen = 112, | ||
Fifteen = 120, | ||
Sixteen = 128 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace Bit.Butil; | ||
|
||
public enum CryptoAlgorithm | ||
{ | ||
RsaOaem, | ||
AesCtr, | ||
AesCbc, | ||
AesGcm | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace Bit.Butil; | ||
|
||
public enum CryptoKeyHash | ||
{ | ||
Sha256, | ||
Sha384, | ||
Sha512, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace Bit.Butil; | ||
|
||
public interface ICryptoAlgorithmParams | ||
{ | ||
string Name { get; } | ||
} |
17 changes: 17 additions & 0 deletions
17
src/Butil/Bit.Butil/Publics/Crypto/RsaOaepCryptoAlgorithmParams.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
namespace Bit.Butil; | ||
|
||
/// <summary> | ||
/// Represents the object that should be passed as the algorithm parameter into Crypto APIs when using the RSA_OAEP algorithm. | ||
/// <br/> | ||
/// <see href="https://developer.mozilla.org/en-US/docs/Web/API/RsaOaepParams">https://developer.mozilla.org/en-US/docs/Web/API/RsaOaepParams</see> | ||
/// </summary> | ||
public class RsaOaepCryptoAlgorithmParams : ICryptoAlgorithmParams | ||
{ | ||
public string Name => "RSA-OAEP"; | ||
|
||
/// <summary> | ||
/// An array of bytes that does not itself need to be encrypted but which should be bound to the ciphertext. | ||
/// A digest of the label is part of the input to the encryption operation. | ||
/// </summary> | ||
public byte[] Label { get; set; } = default!; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
var BitButil = BitButil || {}; | ||
|
||
(function (butil: any) { | ||
crypto.subtle.generateKey | ||
butil.crypto = { | ||
encryptRsaOaep(algorithm, key, data, keyHash) { return endecryptRsaOaep(algorithm, key, data, keyHash, "encrypt") }, | ||
decryptRsaOaep(algorithm, key, data, keyHash) { return endecryptRsaOaep(algorithm, key, data, keyHash, "decrypt") }, | ||
|
||
encryptAesCtr(algorithm, key, data) { return endecryptAesCtr(algorithm, key, data, "encrypt") }, | ||
decryptAesCtr(algorithm, key, data) { return endecryptAesCtr(algorithm, key, data, "decrypt") }, | ||
|
||
encryptAesCbc(algorithm, key, data) { return endecryptAesCbc(algorithm, key, data, "encrypt") }, | ||
decryptAesCbc(algorithm, key, data) { return endecryptAesCbc(algorithm, key, data, "decrypt") }, | ||
|
||
encryptAesGcm(algorithm, key, data) { return endecryptAesGcm(algorithm, key, data, "encrypt") }, | ||
decryptAesGcm(algorithm, key, data) { return endecryptAesGcm(algorithm, key, data, "decrypt") }, | ||
}; | ||
|
||
async function endecryptRsaOaep(algorithm, key, data, keyHash, func) { | ||
const cryptoAlgorithm = { | ||
name: algorithm.name, | ||
label: algorithm.label?.buffer | ||
} | ||
|
||
const keyAlgorithm = { name: "RSA-OAEP", hash: keyHash ?? "SHA-256" }; | ||
|
||
return await endecrypt(cryptoAlgorithm, key, data, keyAlgorithm, func); | ||
} | ||
|
||
async function endecryptAesCtr(algorithm, key, data, func) { | ||
const cryptoAlgorithm = { | ||
name: algorithm.name, | ||
counter: algorithm.counter?.buffer, | ||
length: algorithm.length | ||
} | ||
|
||
const keyAlgorithm = { name: "AES-CTR" }; | ||
|
||
return await endecrypt(cryptoAlgorithm, key, data, keyAlgorithm, func); | ||
} | ||
|
||
async function endecryptAesCbc(algorithm, key, data, func) { | ||
const cryptoAlgorithm = { | ||
name: algorithm.name, | ||
iv: algorithm.iv?.buffer, | ||
} | ||
|
||
const keyAlgorithm = { name: "AES-CBC" }; | ||
|
||
return await endecrypt(cryptoAlgorithm, key, data, keyAlgorithm, func); | ||
} | ||
|
||
async function endecryptAesGcm(algorithm, key, data, func) { | ||
const cryptoAlgorithm = { | ||
name: algorithm.name, | ||
iv: algorithm.iv?.buffer, | ||
additionalData: algorithm.additionalData?.buffer, | ||
tagLength: algorithm.tagLength, | ||
} | ||
|
||
const keyAlgorithm = { name: "AES-GCM" }; | ||
|
||
return await endecrypt(cryptoAlgorithm, key, data, keyAlgorithm, func); | ||
} | ||
|
||
async function endecrypt(cryptoAlgorithm, key, data, keyAlgorithm, func) { | ||
const cryptoKey = await crypto.subtle.importKey("raw", key.buffer, keyAlgorithm, false, ["encrypt", "decrypt"]); | ||
|
||
const buffer = await window.crypto.subtle[func](cryptoAlgorithm, cryptoKey, data.buffer); | ||
|
||
return new Uint8Array(buffer); | ||
} | ||
|
||
|
||
}(BitButil)); |
Oops, something went wrong.