Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
ECDsaCng.cs
Go to the documentation of this file.
1using System.IO;
4
6
7public sealed class ECDsaCng : ECDsa
8{
9 private CngAlgorithmCore _core = new CngAlgorithmCore("ECDsaCng");
10
12
14 {
15 get
16 {
17 return _hashAlgorithm;
18 }
19 set
20 {
21 _hashAlgorithm = value ?? throw new ArgumentNullException("value");
22 }
23 }
24
25 public CngKey Key
26 {
27 get
28 {
29 return GetKey();
30 }
31 private set
32 {
33 if (value == null)
34 {
35 throw new ArgumentNullException("value");
36 }
37 if (!IsEccAlgorithmGroup(value.AlgorithmGroup))
38 {
40 }
42 ForceSetKeySize(value.KeySize);
43 }
44 }
45
46 public override int KeySize
47 {
48 get
49 {
50 return base.KeySize;
51 }
52 set
53 {
54 if (KeySize != value)
55 {
56 base.KeySize = value;
57 DisposeKey();
58 }
59 }
60 }
61
62 public override KeySizes[] LegalKeySizes => new KeySizes[2]
63 {
64 new KeySizes(256, 384, 128),
65 new KeySizes(521, 521, 0)
66 };
67
69 {
70 if (key == null)
71 {
72 throw new ArgumentNullException("key");
73 }
74 if (!IsEccAlgorithmGroup(key.AlgorithmGroup))
75 {
77 }
79 }
80
81 protected override void Dispose(bool disposing)
82 {
83 _core.Dispose();
84 }
85
86 private void ThrowIfDisposed()
87 {
89 }
90
91 private void DisposeKey()
92 {
94 }
95
96 private static bool IsEccAlgorithmGroup(CngAlgorithmGroup algorithmGroup)
97 {
98 if (!(algorithmGroup == CngAlgorithmGroup.ECDsa))
99 {
100 return algorithmGroup == CngAlgorithmGroup.ECDiffieHellman;
101 }
102 return true;
103 }
104
105 internal string GetCurveName(out string oidValue)
106 {
107 return Key.GetCurveName(out oidValue);
108 }
109
110 private void ImportFullKeyBlob(byte[] ecfullKeyBlob, bool includePrivateParameters)
111 {
112 Key = System.Security.Cryptography.ECCng.ImportFullKeyBlob(ecfullKeyBlob, includePrivateParameters);
113 }
114
115 private void ImportKeyBlob(byte[] ecfullKeyBlob, string curveName, bool includePrivateParameters)
116 {
117 Key = System.Security.Cryptography.ECCng.ImportKeyBlob(ecfullKeyBlob, curveName, includePrivateParameters);
118 }
119
120 private byte[] ExportKeyBlob(bool includePrivateParameters)
121 {
122 return System.Security.Cryptography.ECCng.ExportKeyBlob(Key, includePrivateParameters);
123 }
124
125 private byte[] ExportFullKeyBlob(bool includePrivateParameters)
126 {
127 return System.Security.Cryptography.ECCng.ExportFullKeyBlob(Key, includePrivateParameters);
128 }
129
131 {
132 Key = response.Key;
133 }
134
135 public override bool TryExportPkcs8PrivateKey(Span<byte> destination, out int bytesWritten)
136 {
137 return Key.TryExportKeyBlob("PKCS8_PRIVATEKEY", destination, out bytesWritten);
138 }
139
140 private byte[] ExportEncryptedPkcs8(ReadOnlySpan<char> pkcs8Password, int kdfCount)
141 {
142 return Key.ExportPkcs8KeyBlob(pkcs8Password, kdfCount);
143 }
144
145 private bool TryExportEncryptedPkcs8(ReadOnlySpan<char> pkcs8Password, int kdfCount, Span<byte> destination, out int bytesWritten)
146 {
147 return Key.TryExportPkcs8KeyBlob(pkcs8Password, kdfCount, destination, out bytesWritten);
148 }
149
150 public void FromXmlString(string xml, ECKeyXmlFormat format)
151 {
153 }
154
155 public byte[] SignData(byte[] data)
156 {
157 return SignData(data, new HashAlgorithmName(HashAlgorithm.Algorithm));
158 }
159
160 public byte[] SignData(byte[] data, int offset, int count)
161 {
162 return SignData(data, offset, count, new HashAlgorithmName(HashAlgorithm.Algorithm));
163 }
164
165 public byte[] SignData(Stream data)
166 {
167 return SignData(data, new HashAlgorithmName(HashAlgorithm.Algorithm));
168 }
169
171 {
173 }
174
175 public bool VerifyData(byte[] data, byte[] signature)
176 {
177 return VerifyData(data, signature, new HashAlgorithmName(HashAlgorithm.Algorithm));
178 }
179
180 public bool VerifyData(byte[] data, int offset, int count, byte[] signature)
181 {
182 return VerifyData(data, offset, count, signature, new HashAlgorithmName(HashAlgorithm.Algorithm));
183 }
184
185 public bool VerifyData(Stream data, byte[] signature)
186 {
187 return VerifyData(data, signature, new HashAlgorithmName(HashAlgorithm.Algorithm));
188 }
189
190 public override void GenerateKey(ECCurve curve)
191 {
192 curve.Validate();
194 if (curve.IsNamed)
195 {
196 if (string.IsNullOrEmpty(curve.Oid.FriendlyName))
197 {
199 }
201 if (CngKey.IsECNamedCurve(cngAlgorithm.Algorithm))
202 {
203 CngKey orGenerateKey = _core.GetOrGenerateKey(curve);
204 ForceSetKeySize(orGenerateKey.KeySize);
205 return;
206 }
207 int num = 0;
208 if (cngAlgorithm == CngAlgorithm.ECDsaP256)
209 {
210 num = 256;
211 }
212 else if (cngAlgorithm == CngAlgorithm.ECDsaP384)
213 {
214 num = 384;
215 }
216 else
217 {
218 if (!(cngAlgorithm == CngAlgorithm.ECDsaP521))
219 {
221 }
222 num = 521;
223 }
224 _core.GetOrGenerateKey(num, cngAlgorithm);
225 ForceSetKeySize(num);
226 }
227 else
228 {
229 if (!curve.IsExplicit)
230 {
232 }
233 CngKey orGenerateKey2 = _core.GetOrGenerateKey(curve);
234 ForceSetKeySize(orGenerateKey2.KeySize);
235 }
236 }
237
238 private CngKey GetKey()
239 {
240 CngKey cngKey = null;
242 {
243 return _core.GetOrGenerateKey(null);
244 }
245 CngAlgorithm cngAlgorithm = null;
246 int num = 0;
247 num = KeySize;
248 cngAlgorithm = num switch
249 {
250 256 => CngAlgorithm.ECDsaP256,
251 384 => CngAlgorithm.ECDsaP384,
252 521 => CngAlgorithm.ECDsaP521,
254 };
255 return _core.GetOrGenerateKey(num, cngAlgorithm);
256 }
257
259 {
260 return Key.Handle;
261 }
262
263 public override void ImportParameters(ECParameters parameters)
264 {
265 parameters.Validate();
267 ECCurve curve = parameters.Curve;
268 bool flag = parameters.D != null;
269 bool flag2 = parameters.Q.X != null && parameters.Q.Y != null;
270 if (curve.IsPrime)
271 {
272 if (!flag2 && flag)
273 {
274 byte[] array = new byte[parameters.D.Length];
275 ECParameters parameters2 = parameters;
276 parameters2.Q.X = array;
277 parameters2.Q.Y = array;
278 byte[] primeCurveBlob = System.Security.Cryptography.ECCng.GetPrimeCurveBlob(ref parameters2, ecdh: false);
279 ImportFullKeyBlob(primeCurveBlob, includePrivateParameters: true);
280 }
281 else
282 {
283 byte[] primeCurveBlob2 = System.Security.Cryptography.ECCng.GetPrimeCurveBlob(ref parameters, ecdh: false);
284 ImportFullKeyBlob(primeCurveBlob2, flag);
285 }
286 return;
287 }
288 if (curve.IsNamed)
289 {
290 if (string.IsNullOrEmpty(curve.Oid.FriendlyName))
291 {
293 }
294 if (!flag2 && flag)
295 {
296 byte[] array2 = new byte[parameters.D.Length];
297 ECParameters parameters3 = parameters;
298 parameters3.Q.X = array2;
299 parameters3.Q.Y = array2;
300 byte[] namedCurveBlob = System.Security.Cryptography.ECCng.GetNamedCurveBlob(ref parameters3, ecdh: false);
301 ImportKeyBlob(namedCurveBlob, curve.Oid.FriendlyName, includePrivateParameters: true);
302 }
303 else
304 {
305 byte[] namedCurveBlob2 = System.Security.Cryptography.ECCng.GetNamedCurveBlob(ref parameters, ecdh: false);
306 ImportKeyBlob(namedCurveBlob2, curve.Oid.FriendlyName, flag);
307 }
308 return;
309 }
311 }
312
313 public override ECParameters ExportExplicitParameters(bool includePrivateParameters)
314 {
315 byte[] ecBlob = ExportFullKeyBlob(includePrivateParameters);
316 ECParameters ecParams = default(ECParameters);
317 System.Security.Cryptography.ECCng.ExportPrimeCurveParameters(ref ecParams, ecBlob, includePrivateParameters);
318 return ecParams;
319 }
320
321 public override ECParameters ExportParameters(bool includePrivateParameters)
322 {
323 ECParameters ecParams = default(ECParameters);
324 string oidValue;
325 string curveName = GetCurveName(out oidValue);
326 if (string.IsNullOrEmpty(curveName))
327 {
328 byte[] ecBlob = ExportFullKeyBlob(includePrivateParameters);
329 System.Security.Cryptography.ECCng.ExportPrimeCurveParameters(ref ecParams, ecBlob, includePrivateParameters);
330 }
331 else
332 {
333 byte[] ecBlob2 = ExportKeyBlob(includePrivateParameters);
334 System.Security.Cryptography.ECCng.ExportNamedCurveParameters(ref ecParams, ecBlob2, includePrivateParameters);
335 ecParams.Curve = ECCurve.CreateFromOid(new Oid(oidValue, curveName));
336 }
337 return ecParams;
338 }
339
340 public override void ImportPkcs8PrivateKey(ReadOnlySpan<byte> source, out int bytesRead)
341 {
343 int bytesRead2;
345 ProcessPkcs8Response(response);
346 bytesRead = bytesRead2;
347 }
348
349 public override void ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, ReadOnlySpan<byte> source, out int bytesRead)
350 {
352 int bytesRead2;
354 ProcessPkcs8Response(response);
355 bytesRead = bytesRead2;
356 }
357
358 public override void ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, ReadOnlySpan<byte> source, out int bytesRead)
359 {
361 int bytesRead2;
363 ProcessPkcs8Response(response);
364 bytesRead = bytesRead2;
365 }
366
368 {
369 string algorithmGroup = response.GetAlgorithmGroup();
370 if (algorithmGroup == "ECDSA" || algorithmGroup == "ECDH")
371 {
372 AcceptImport(response);
373 return;
374 }
375 response.FreeKey();
377 }
378
379 public override byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters)
380 {
381 if (pbeParameters == null)
382 {
383 throw new ArgumentNullException("pbeParameters");
384 }
385 return System.Security.Cryptography.CngPkcs8.ExportEncryptedPkcs8PrivateKey(this, passwordBytes, pbeParameters);
386 }
387
388 public override byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, PbeParameters pbeParameters)
389 {
390 if (pbeParameters == null)
391 {
392 throw new ArgumentNullException("pbeParameters");
393 }
396 {
397 return ExportEncryptedPkcs8(password, pbeParameters.IterationCount);
398 }
399 return System.Security.Cryptography.CngPkcs8.ExportEncryptedPkcs8PrivateKey(this, password, pbeParameters);
400 }
401
402 public override bool TryExportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters, Span<byte> destination, out int bytesWritten)
403 {
404 if (pbeParameters == null)
405 {
406 throw new ArgumentNullException("pbeParameters");
407 }
409 return System.Security.Cryptography.CngPkcs8.TryExportEncryptedPkcs8PrivateKey(this, passwordBytes, pbeParameters, destination, out bytesWritten);
410 }
411
412 public override bool TryExportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, PbeParameters pbeParameters, Span<byte> destination, out int bytesWritten)
413 {
414 if (pbeParameters == null)
415 {
416 throw new ArgumentNullException("pbeParameters");
417 }
420 {
421 return TryExportEncryptedPkcs8(password, pbeParameters.IterationCount, destination, out bytesWritten);
422 }
423 return System.Security.Cryptography.CngPkcs8.TryExportEncryptedPkcs8PrivateKey(this, password, pbeParameters, destination, out bytesWritten);
424 }
425
426 public ECDsaCng(ECCurve curve)
427 {
428 GenerateKey(curve);
429 }
430
431 public ECDsaCng()
432 : this(521)
433 {
434 }
435
436 public ECDsaCng(int keySize)
437 {
438 KeySize = keySize;
439 }
440
441 private void ForceSetKeySize(int newKeySize)
442 {
443 KeySizeValue = newKeySize;
444 }
445
446 protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
447 {
448 return Internal.Cryptography.CngCommon.HashData(data, offset, count, hashAlgorithm);
449 }
450
451 protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm)
452 {
453 return Internal.Cryptography.CngCommon.HashData(data, hashAlgorithm);
454 }
455
456 protected override bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
457 {
458 return Internal.Cryptography.CngCommon.TryHashData(source, destination, hashAlgorithm, out bytesWritten);
459 }
460
461 public unsafe override byte[] SignHash(byte[] hash)
462 {
463 if (hash == null)
464 {
465 throw new ArgumentNullException("hash");
466 }
467 int estimatedSize = KeySize switch
468 {
469 256 => 64,
470 384 => 96,
471 521 => 132,
472 _ => KeySize / 4,
473 };
475 return keyHandle.SignHash(hash, global::Interop.NCrypt.AsymmetricPaddingMode.None, null, estimatedSize);
476 }
477
478 public unsafe override bool TrySignHash(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
479 {
480 using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
481 {
482 if (!keyHandle.TrySignHash(source, destination, global::Interop.NCrypt.AsymmetricPaddingMode.None, null, out bytesWritten))
483 {
484 bytesWritten = 0;
485 return false;
486 }
487 }
488 return true;
489 }
490
491 public override bool VerifyHash(byte[] hash, byte[] signature)
492 {
493 if (hash == null)
494 {
495 throw new ArgumentNullException("hash");
496 }
497 if (signature == null)
498 {
499 throw new ArgumentNullException("signature");
500 }
501 return VerifyHash((ReadOnlySpan<byte>)hash, (ReadOnlySpan<byte>)signature);
502 }
503
504 public unsafe override bool VerifyHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature)
505 {
507 return keyHandle.VerifyHash(hash, signature, global::Interop.NCrypt.AsymmetricPaddingMode.None, null);
508 }
509}
static byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
Definition CngCommon.cs:10
static bool TryHashData(ReadOnlySpan< byte > source, Span< byte > destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
Definition CngCommon.cs:17
static string Cryptography_CurveNotSupported
Definition SR.cs:64
static string Format(string resourceFormat, object p1)
Definition SR.cs:118
static string Cryptography_NotValidPublicOrPrivateKey
Definition SR.cs:122
static string Cryptography_ArgECDsaRequiresECDsaKey
Definition SR.cs:36
static string Cryptography_InvalidCurveOid
Definition SR.cs:66
static string Cryptography_InvalidKeySize
Definition SR.cs:92
Definition SR.cs:7
bool TryExportKeyBlob(string blobType, Span< byte > destination, out int bytesWritten)
Definition CngKey.cs:643
static CngAlgorithm EcdsaCurveNameToAlgorithm(string name)
Definition CngKey.cs:489
string GetCurveName(out string oidValue)
Definition CngKey.cs:450
byte[] ExportPkcs8KeyBlob(ReadOnlySpan< char > password, int kdfCount)
Definition CngKey.cs:665
bool TryExportPkcs8KeyBlob(ReadOnlySpan< char > password, int kdfCount, Span< byte > destination, out int bytesWritten)
Definition CngKey.cs:673
SafeNCryptKeyHandle Handle
Definition CngKey.cs:51
static bool IsPlatformScheme(PbeParameters pbeParameters)
Definition CngPkcs8.cs:44
static unsafe Pkcs8Response ImportEncryptedPkcs8PrivateKey(ReadOnlySpan< byte > passwordBytes, ReadOnlySpan< byte > source, out int bytesRead)
Definition CngPkcs8.cs:134
static byte[] ExportEncryptedPkcs8PrivateKey(AsymmetricAlgorithm key, ReadOnlySpan< byte > passwordBytes, PbeParameters pbeParameters)
Definition CngPkcs8.cs:53
static Pkcs8Response ImportPkcs8PrivateKey(ReadOnlySpan< byte > source, out int bytesRead)
Definition CngPkcs8.cs:90
static bool TryExportEncryptedPkcs8PrivateKey(AsymmetricAlgorithm key, ReadOnlySpan< byte > passwordBytes, PbeParameters pbeParameters, Span< byte > destination, out int bytesWritten)
Definition CngPkcs8.cs:68
static SafeNCryptKeyHandle ImportKeyBlob(string blobType, ReadOnlySpan< byte > keyBlob, string curveName, SafeNCryptProviderHandle provider)
Definition ECCng.cs:307
static unsafe byte[] GetPrimeCurveBlob(ref ECParameters parameters, bool ecdh)
Definition ECCng.cs:88
static CngKey ImportFullKeyBlob(byte[] ecBlob, bool includePrivateParameters)
Definition ECCng.cs:17
static unsafe void ExportNamedCurveParameters(ref ECParameters ecParams, byte[] ecBlob, bool includePrivateParameters)
Definition ECCng.cs:131
static byte[] ExportKeyBlob(CngKey key, bool includePrivateParameters)
Definition ECCng.cs:25
static unsafe byte[] GetNamedCurveBlob(ref ECParameters parameters, bool ecdh)
Definition ECCng.cs:63
static unsafe void ExportPrimeCurveParameters(ref ECParameters ecParams, byte[] ecBlob, bool includePrivateParameters)
Definition ECCng.cs:155
static byte[] ExportFullKeyBlob(CngKey key, bool includePrivateParameters)
Definition ECCng.cs:31
static bool IsEccAlgorithmGroup(CngAlgorithmGroup algorithmGroup)
Definition ECDsaCng.cs:96
override void ImportEncryptedPkcs8PrivateKey(ReadOnlySpan< byte > passwordBytes, ReadOnlySpan< byte > source, out int bytesRead)
Definition ECDsaCng.cs:349
override bool TryExportEncryptedPkcs8PrivateKey(ReadOnlySpan< char > password, PbeParameters pbeParameters, Span< byte > destination, out int bytesWritten)
Definition ECDsaCng.cs:412
SafeNCryptKeyHandle GetDuplicatedKeyHandle()
Definition ECDsaCng.cs:258
unsafe override bool VerifyHash(ReadOnlySpan< byte > hash, ReadOnlySpan< byte > signature)
Definition ECDsaCng.cs:504
byte[] ExportEncryptedPkcs8(ReadOnlySpan< char > pkcs8Password, int kdfCount)
Definition ECDsaCng.cs:140
override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm)
Definition ECDsaCng.cs:451
override byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan< char > password, PbeParameters pbeParameters)
Definition ECDsaCng.cs:388
bool TryExportEncryptedPkcs8(ReadOnlySpan< char > pkcs8Password, int kdfCount, Span< byte > destination, out int bytesWritten)
Definition ECDsaCng.cs:145
void ProcessPkcs8Response(System.Security.Cryptography.CngPkcs8.Pkcs8Response response)
Definition ECDsaCng.cs:367
bool VerifyData(byte[] data, byte[] signature)
Definition ECDsaCng.cs:175
override ECParameters ExportParameters(bool includePrivateParameters)
Definition ECDsaCng.cs:321
bool VerifyData(byte[] data, int offset, int count, byte[] signature)
Definition ECDsaCng.cs:180
override byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan< byte > passwordBytes, PbeParameters pbeParameters)
Definition ECDsaCng.cs:379
unsafe override bool TrySignHash(ReadOnlySpan< byte > source, Span< byte > destination, out int bytesWritten)
Definition ECDsaCng.cs:478
override bool TryExportEncryptedPkcs8PrivateKey(ReadOnlySpan< byte > passwordBytes, PbeParameters pbeParameters, Span< byte > destination, out int bytesWritten)
Definition ECDsaCng.cs:402
override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
Definition ECDsaCng.cs:446
override void ImportEncryptedPkcs8PrivateKey(ReadOnlySpan< char > password, ReadOnlySpan< byte > source, out int bytesRead)
Definition ECDsaCng.cs:358
void ImportFullKeyBlob(byte[] ecfullKeyBlob, bool includePrivateParameters)
Definition ECDsaCng.cs:110
override void ImportPkcs8PrivateKey(ReadOnlySpan< byte > source, out int bytesRead)
Definition ECDsaCng.cs:340
byte[] ExportFullKeyBlob(bool includePrivateParameters)
Definition ECDsaCng.cs:125
unsafe override byte[] SignHash(byte[] hash)
Definition ECDsaCng.cs:461
override void ImportParameters(ECParameters parameters)
Definition ECDsaCng.cs:263
override ECParameters ExportExplicitParameters(bool includePrivateParameters)
Definition ECDsaCng.cs:313
void ImportKeyBlob(byte[] ecfullKeyBlob, string curveName, bool includePrivateParameters)
Definition ECDsaCng.cs:115
bool VerifyData(Stream data, byte[] signature)
Definition ECDsaCng.cs:185
void AcceptImport(System.Security.Cryptography.CngPkcs8.Pkcs8Response response)
Definition ECDsaCng.cs:130
byte[] ExportKeyBlob(bool includePrivateParameters)
Definition ECDsaCng.cs:120
override bool TryHashData(ReadOnlySpan< byte > source, Span< byte > destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
Definition ECDsaCng.cs:456
void FromXmlString(string xml, ECKeyXmlFormat format)
Definition ECDsaCng.cs:150
override KeySizes[] LegalKeySizes
Definition ECDsaCng.cs:62
override void Dispose(bool disposing)
Definition ECDsaCng.cs:81
override void GenerateKey(ECCurve curve)
Definition ECDsaCng.cs:190
string ToXmlString(ECKeyXmlFormat format)
Definition ECDsaCng.cs:170
override bool TryExportPkcs8PrivateKey(Span< byte > destination, out int bytesWritten)
Definition ECDsaCng.cs:135
override bool VerifyHash(byte[] hash, byte[] signature)
Definition ECDsaCng.cs:491
string GetCurveName(out string oidValue)
Definition ECDsaCng.cs:105
void ForceSetKeySize(int newKeySize)
Definition ECDsaCng.cs:441
byte[] SignData(byte[] data, int offset, int count)
Definition ECDsaCng.cs:160
static void ValidatePbeParameters(PbeParameters pbeParameters, ReadOnlySpan< char > password, ReadOnlySpan< byte > passwordBytes)
CngKey GetOrGenerateKey(int keySize, CngAlgorithm algorithm)
static ECCurve CreateFromOid(Oid curveOid)
Definition ECCurve.cs:127