-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPGCT.cs
More file actions
157 lines (138 loc) · 6.05 KB
/
Copy pathPGCT.cs
File metadata and controls
157 lines (138 loc) · 6.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// SPDX-FileCopyrightText: 2017-2020 Melbot Studios, S.L.
// SPDX-License-Identifier: LicenseRef-Melbot-Portfolio
//
// Original author: Miguel Angel Exposito (2017-2020)
//
// This source code is the property of Melbot Studios, S.L. and is published
// publicly for portfolio and educational review purposes with the express
// written authorization of Melbot Studios, S.L.
//
// All rights remain with Melbot Studios, S.L. Redistribution, modification,
// commercial use, or derivative works are not permitted without prior
// written consent of the copyright holder. See LICENSE for full terms.
//
// Note: this C# implementation mirrors the AES-CTR helper in the firmware
// (`Main/Project/src/HAL/Crypt.c`, adapted from Nordic Semiconductor's
// DevZone reference). The structure, parameter conventions, and inline
// doxygen comments — including the `NRF_*` retval names that are not
// applicable on this side — are intentionally kept aligned with the
// firmware-side documentation for cross-reference.
using System.Security.Cryptography;
using System;
using System.IO;
namespace Melbot.PodLib
{
class PGCT
{
const uint KeyLen = 16;
const uint CtrByteLen = 4;
const uint NonceRandByteLen = 12;
static bool _isInitialized = false;
byte[] _ecbDataKey;
byte[] _ecbClearText;
readonly byte[] _zeros = new byte[16];
ICryptoTransform _cTransform;
Aes _aes;
/**
* @brief Initializes the module with the given nonce and key
* @details The nonce will be copied to an internal buffer so it does not need to
* be retained after the function returns. Additionally, a 32-bit counter
* will be initialized to zero and placed into the least-significant 4 bytes
* of the internal buffer. The nonce value should be generated in a
* reasonable manner (e.g. using this module's nonce_generate function).
*
* @param[in] p_nonce An array of length 16 containing 12 random bytes
* starting at index 4
* @param[in] p_ecb_key An array of length 16 containing the ECB key
*/
public void CtrInit(byte[] nonce, byte[] key)
{
_isInitialized = true;
_ecbDataKey = key.Clone() as byte[];
_ecbClearText = new byte[CtrByteLen + NonceRandByteLen];
Array.Copy(nonce, 0, _ecbClearText, CtrByteLen, NonceRandByteLen);
// Zero the counter value.
// No need to do this
_aes = Aes.Create();
_aes.Mode = CipherMode.ECB;
_cTransform = _aes.CreateEncryptor(_ecbDataKey, _zeros);
}
public void CtrDeInit()
{
_isInitialized = false;
_ecbDataKey = null;
_ecbClearText = null;
_aes?.Clear();
_aes?.Dispose();
_aes = null;
}
void Cpt(byte[] buf, ref uint ctr)
{
if (!_isInitialized) throw new InvalidOperationException();
// Write the counter to the cleartext
using (var ms = new MemoryStream(_ecbClearText))
{
using (var wr = new BinaryWriter(ms))
wr.Write(ctr);
}
uint i = 0;
while (i < buf.Length)
{
byte[] resultArray;
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, _cTransform, CryptoStreamMode.Write))
{
csEncrypt.Write(_ecbClearText, 0, _ecbClearText.Length);
resultArray = msEncrypt.ToArray();
}
}
for (uint j = 0; i < buf.Length && j < KeyLen; ++i, ++j)
{
buf[i] ^= resultArray[j];
}
//uint ctr = 0;
// Increment the counter.
using (var ms = new MemoryStream(_ecbClearText))
{
ms.Seek(0, SeekOrigin.Begin);
++ctr;
using (var wr = new BinaryWriter(ms))
wr.Write(ctr);
}
}
}
/**
* @brief Encrypts the given buffer in-situ
* @details The encryption step is done separately (using the nonce, counter, and
* key) and then the result from the encryption is XOR'd with the given
* buffer in-situ. The counter will be incremented only if no error occurs.
*
* @param[in] p_clear_text An array of length 16 containing the clear text
*
* @retval NRF_SUCCESS Success
* @retval NRF_ERROR_INVALID_STATE Module has not been initialized
* @retval NRF_ERROR_SOFTDEVICE_NOT_ENABLED SoftDevice is present, but not enabled
*/
public void Ect(byte[] pCt, ref uint ctr)
{
Cpt(pCt, ref ctr);
}
/**
* @brief Decrypts the given buffer in-situ
* @details The encryption step is done separately (using the nonce, counter, and
* key) and then the result from the encryption is XOR'd with the given
* buffer in-situ. The counter will be incremented only if no error occurs.
*
* @param[in] p_cipher_text An array of length 16 containing the cipher text
*
* @retval NRF_SUCCESS Succeess
* @retval NRF_ERROR_INVALID_STATE Module has not been initialized
* @retval NRF_ERROR_SOFTDEVICE_NOT_ENABLED SoftDevice is present, but not enabled *
*/
public void Dct(byte[] pCt, ref uint ctr)
{
Cpt(pCt, ref ctr);
}
}
}