-
Notifications
You must be signed in to change notification settings - Fork 862
/
AmazonCloudFrontUrlSigner.cs
552 lines (517 loc) · 30.1 KB
/
AmazonCloudFrontUrlSigner.cs
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Amazon.CloudFront.Model;
using Amazon.Runtime;
using Amazon.Util;
using ThirdParty.BouncyCastle.OpenSsl;
using System.Globalization;
#pragma warning disable 1591
namespace Amazon.CloudFront
{
/// <summary>
/// This utility class provides methods for creating signed URLs for
/// Amazon CloudFront distributions using canned or custom policies.
/// </summary>
public static class AmazonCloudFrontUrlSigner
{
public enum Protocol
{
http, https, rtmp
}
/// <summary>
/// Returns a signed URL that grants universal access to private content until a given date.
/// </summary>
/// <param name="protocol">The protocol of the URL</param>
/// <param name="distributionDomain">The domain name of the distribution</param>
/// <param name="resourcePath">The path for the resource, or the name of the stream for rtmp</param>
/// <param name="privateKey">The private key file. RSA private key (.pem) are supported.</param>
/// <param name="keyPairId">The key pair id corresponding to the private key file given.</param>
/// <param name="expiresOn">The expiration date of the signed URL</param>
/// <returns>The signed URL.</returns>
public static string GetCannedSignedURL(Protocol protocol,
string distributionDomain,
FileSystemInfo privateKey,
string resourcePath,
string keyPairId,
DateTime expiresOn)
{
using (StreamReader reader = new StreamReader(File.OpenRead(privateKey.FullName)))
{
return GetCannedSignedURL(protocol, distributionDomain, reader, resourcePath, keyPairId, expiresOn);
}
}
/// <summary>
/// Returns a signed URL that grants universal access to private content until a given date.
/// </summary>
/// <param name="protocol">The protocol of the URL</param>
/// <param name="distributionDomain">The domain name of the distribution</param>
/// <param name="resourcePath">The path for the resource, or the name of the stream for rtmp</param>
/// <param name="privateKey">The private key file. RSA private key (.pem) are supported.</param>
/// <param name="keyPairId">The key pair id corresponding to the private key file given.</param>
/// <param name="expiresOn">The expiration date of the signed URL</param>
/// <returns>The signed URL.</returns>
public static string GetCannedSignedURL(Protocol protocol,
string distributionDomain,
TextReader privateKey,
string resourcePath,
string keyPairId,
DateTime expiresOn)
{
string url = GenerateResourcePath(protocol, distributionDomain, resourcePath);
return GetCannedSignedURL(url, privateKey, keyPairId, expiresOn);
}
/// <summary>
/// Returns a signed URL that grants universal access to private content until a given date.
/// </summary>
/// <param name="url">The full url (protocol + domain + resource path) to the resource, or the name of the stream for rtmp</param>
/// <param name="privateKey">The private key file. RSA private key (.pem) are supported.</param>
/// <param name="keyPairId">The key pair id corresponding to the private key file given.</param>
/// <param name="expiresOn">The expiration date of the signed URL</param>
/// <returns>The signed URL.</returns>
public static string GetCannedSignedURL(string url,
TextReader privateKey,
string keyPairId,
DateTime expiresOn)
{
string signedUrlCanned = SignUrlCanned(url, keyPairId, privateKey, expiresOn);
return signedUrlCanned;
}
/// <summary>
/// Returns a signed URL that provides tailored access to private content based on an access time window and an ip range.
/// </summary>
/// <param name="protocol">The protocol of the URL</param>
/// <param name="distributionDomain">The domain name of the distribution</param>
/// <param name="privateKey">Your private key file. RSA private key (.pem) are supported.</param>
/// <param name="resourcePath">The path for the resource, or the name of the stream for rtmp</param>
/// <param name="keyPairId">The key pair id corresponding to the private key file given</param>
/// <param name="expiresOn">The expiration date of the signed URL</param>
/// <param name="activeFrom">The beginning valid date of the signed URL</param>
/// <param name="ipRange">The allowed IP address range of the client making the GET request, in CIDR form (e.g. 192.168.0.1/24).</param>
/// <returns>The signed URL.</returns>
public static string GetCustomSignedURL(Protocol protocol,
string distributionDomain,
FileSystemInfo privateKey,
string resourcePath,
string keyPairId,
DateTime expiresOn,
DateTime activeFrom,
string ipRange)
{
using (StreamReader reader = new StreamReader(File.OpenRead(privateKey.FullName)))
{
return GetCustomSignedURL(protocol, distributionDomain, reader, resourcePath, keyPairId, expiresOn, activeFrom, ipRange);
}
}
/// <summary>
/// Returns a signed URL that provides tailored access to private content based on an access time window and an ip range.
/// </summary>
/// <param name="protocol">The protocol of the URL</param>
/// <param name="distributionDomain">The domain name of the distribution</param>
/// <param name="privateKey">Your private key file. RSA private key (.pem) are supported.</param>
/// <param name="resourcePath">The path for the resource, or the name of the stream for rtmp</param>
/// <param name="keyPairId">The key pair id corresponding to the private key file given</param>
/// <param name="expiresOn">The expiration date of the signed URL</param>
/// <param name="activeFrom">The beginning valid date of the signed URL</param>
/// <param name="ipRange">The allowed IP address range of the client making the GET request, in CIDR form (e.g. 192.168.0.1/24).</param>
/// <returns>The signed URL.</returns>
public static string GetCustomSignedURL(Protocol protocol,
string distributionDomain,
TextReader privateKey,
string resourcePath,
string keyPairId,
DateTime expiresOn,
DateTime activeFrom,
string ipRange)
{
string path = GenerateResourcePath(protocol, distributionDomain, resourcePath);
return GetCustomSignedURL(path, privateKey, keyPairId, expiresOn, activeFrom, ipRange);
}
/// <summary>
/// Returns a signed URL that provides tailored access to private content based on an access time window and an ip range.
/// </summary>
/// <param name="protocol">The protocol of the URL</param>
/// <param name="distributionDomain">The domain name of the distribution</param>
/// <param name="privateKey">Your private key file. RSA private key (.pem) are supported.</param>
/// <param name="resourcePath">The path for the resource, or the name of the stream for rtmp</param>
/// <param name="keyPairId">The key pair id corresponding to the private key file given</param>
/// <param name="expiresOn">The expiration date of the signed URL</param>
/// <param name="ipRange">The allowed IP address range of the client making the GET request, in CIDR form (e.g. 192.168.0.1/24).</param>
/// <returns>The signed URL.</returns>
public static string GetCustomSignedURL(Protocol protocol,
string distributionDomain,
TextReader privateKey,
string resourcePath,
string keyPairId,
DateTime expiresOn,
string ipRange)
{
string path = GenerateResourcePath(protocol, distributionDomain, resourcePath);
return GetCustomSignedURL(path, privateKey, keyPairId, expiresOn, ipRange);
}
/// <summary>
/// Returns a signed URL that provides tailored access to private content based on an access time window and an ip range.
/// </summary>
/// <param name="url">The protocol of the URL</param>
/// <param name="privateKey">Your private key file. RSA private key (.pem) are supported.</param>
/// <param name="keyPairId">The key pair id corresponding to the private key file given</param>
/// <param name="expiresOn">The expiration date of the signed URL</param>
/// <param name="activeFrom">The beginning valid date of the signed URL</param>
/// <param name="ipRange">The allowed IP address range of the client making the GET request, in CIDR form (e.g. 192.168.0.1/24).</param>
/// <returns>The signed URL.</returns>
public static string GetCustomSignedURL(string url,
TextReader privateKey,
string keyPairId,
DateTime expiresOn,
DateTime activeFrom,
string ipRange)
{
string policy = BuildPolicyForSignedUrl(url, expiresOn, ipRange, activeFrom);
return SignUrl(url, keyPairId, privateKey, policy);
}
/// <summary>
/// Returns a signed URL that provides tailored access to private content based on an access time window and an ip range.
/// </summary>
/// <param name="url">The protocol of the URL</param>
/// <param name="privateKey">Your private key file. RSA private key (.pem) are supported.</param>
/// <param name="keyPairId">The key pair id corresponding to the private key file given</param>
/// <param name="expiresOn">The expiration date of the signed URL</param>
/// <param name="ipRange">The allowed IP address range of the client making the GET request, in CIDR form (e.g. 192.168.0.1/24).</param>
/// <returns>The signed URL.</returns>
public static string GetCustomSignedURL(string url,
TextReader privateKey,
string keyPairId,
DateTime expiresOn,
string ipRange)
{
string policy = BuildPolicyForSignedUrl(url, expiresOn, ipRange);
return SignUrl(url, keyPairId, privateKey, policy);
}
/// <summary>
/// Generate a signed URL that allows access to distribution and resource path
/// by applying access restrictions specified in a custom policy document.
/// </summary>
/// <param name="resourceUrlOrPath">
/// The URL or path that uniquely identifies a resource within a
/// distribution. For standard distributions the resource URL will
/// be <tt>"http://" + distributionName + "/" + path</tt>
/// (may also include URL parameters. For distributions with the
/// HTTPS required protocol, the resource URL must start with
/// <tt>"https://"</tt>. RTMP resources do not take the form of a
/// URL, and instead the resource path is nothing but the stream's
/// name.
/// </param>
/// <param name="keyPairId">Identifier of a public/private certificate keypair already configured in your Amazon Web Services account.</param>
/// <param name="privateKey">The RSA private key data that corresponding to the certificate keypair identified by keyPairId.</param>
/// <param name="policy">A policy document that describes the access permissions that will be applied by
/// the signed URL.</param>
/// <returns>A signed URL that will permit access to distribution and resource path as specified in the policy document.</returns>
public static string SignUrl(string resourceUrlOrPath, string keyPairId, FileInfo privateKey, string policy)
{
using (StreamReader reader = new StreamReader(File.OpenRead(privateKey.FullName)))
{
return SignUrl(resourceUrlOrPath, keyPairId, reader, policy);
}
}
/// <summary>
/// Generate a signed URL that allows access to distribution and resource path
/// by applying access restrictions specified in a custom policy document.
/// </summary>
/// <param name="resourceUrlOrPath">
/// The URL or path that uniquely identifies a resource within a
/// distribution. For standard distributions the resource URL will
/// be <tt>"http://" + distributionName + "/" + path</tt>
/// (may also include URL parameters. For distributions with the
/// HTTPS required protocol, the resource URL must start with
/// <tt>"https://"</tt>. RTMP resources do not take the form of a
/// URL, and instead the resource path is nothing but the stream's
/// name.
/// </param>
/// <param name="keyPairId">Identifier of a public/private certificate keypair already configured in your Amazon Web Services account.</param>
/// <param name="privateKey">The RSA private key data that corresponding to the certificate keypair identified by keyPairId.</param>
/// <param name="policy">A policy document that describes the access permissions that will be applied by
/// the signed URL.</param>
/// <returns>A signed URL that will permit access to distribution and S3 objects as specified in the policy document.</returns>
public static string SignUrl(string resourceUrlOrPath, string keyPairId, TextReader privateKey, string policy)
{
RSAParameters rsaParameters = ConvertPEMToRSAParameters(privateKey);
byte[] signatureBytes = SignWithSha1RSA(UTF8Encoding.UTF8.GetBytes(policy), rsaParameters);
string urlSafePolicy = MakeStringUrlSafe(policy);
string urlSafeSignature = MakeBytesUrlSafe(signatureBytes);
string signedUrl = resourceUrlOrPath + (resourceUrlOrPath.IndexOf('?') >= 0 ? "&" : "?") + "Policy="
+ urlSafePolicy + "&Signature=" + urlSafeSignature + "&Key-Pair-Id=" + keyPairId;
return signedUrl;
}
/// <summary>
/// Generate a signed URL that allows access to a specific distribution and
/// resource path by applying a access restrictions from a "canned" (simplified)
/// policy document.
/// </summary>
/// <param name="resourceUrlOrPath">
/// The URL or path that uniquely identifies a resource within a
/// distribution. For standard distributions the resource URL will
/// be <tt>"http://" + distributionName + "/" + path</tt>
/// (may also include URL parameters. For distributions with the
/// HTTPS required protocol, the resource URL must start with
/// <tt>"https://"</tt>. RTMP resources do not take the form of a
/// URL, and instead the resource path is nothing but the stream's
/// name.
/// </param>
/// <param name="keyPairId">Identifier of a public/private certificate keypair already configured in your Amazon Web Services account.</param>
/// <param name="privateKey">The RSA private key data that corresponding to the certificate keypair identified by keyPairId.</param>
/// <param name="expiresOn">The time and date when the signed URL will expire.</param>
public static String SignUrlCanned(string resourceUrlOrPath,
string keyPairId,
FileInfo privateKey,
DateTime expiresOn)
{
using (StreamReader reader = new StreamReader(File.OpenRead(privateKey.FullName)))
{
return SignUrlCanned(resourceUrlOrPath, keyPairId, reader, expiresOn);
}
}
/// <summary>
/// Generate a signed URL that allows access to a specific distribution and
/// resource path by applying a access restrictions from a "canned" (simplified)
/// policy document.
/// </summary>
/// <param name="resourceUrlOrPath">
/// The URL or path that uniquely identifies a resource within a
/// distribution. For standard distributions the resource URL will
/// be <tt>"http://" + distributionName + "/" + path</tt>
/// (may also include URL parameters. For distributions with the
/// HTTPS required protocol, the resource URL must start with
/// <tt>"https://"</tt>. RTMP resources do not take the form of a
/// URL, and instead the resource path is nothing but the stream's
/// name.
/// </param>
/// <param name="keyPairId">Identifier of a public/private certificate keypair already configured in your Amazon Web Services account.</param>
/// <param name="privateKey">The RSA private key data that corresponding to the certificate keypair identified by keyPairId.</param>
/// <param name="expiresOn">The time and date when the signed URL will expire.</param>
public static String SignUrlCanned(string resourceUrlOrPath,
string keyPairId,
TextReader privateKey,
DateTime expiresOn)
{
string epochSeconds = AWSSDKUtils.ConvertToUnixEpochSecondsString(expiresOn.ToUniversalTime());
RSAParameters rsaParameters = ConvertPEMToRSAParameters(privateKey);
string cannedPolicy = "{\"Statement\":[{\"Resource\":\"" + resourceUrlOrPath
+ "\",\"Condition\":{\"DateLessThan\":{\"AWS:EpochTime\":" + epochSeconds
+ "}}}]}";
byte[] signatureBytes = SignWithSha1RSA(UTF8Encoding.UTF8.GetBytes(cannedPolicy), rsaParameters);
string urlSafeSignature = MakeBytesUrlSafe(signatureBytes);
string signedUrl = resourceUrlOrPath + (resourceUrlOrPath.IndexOf('?') >= 0 ? "&" : "?") + "Expires="
+ epochSeconds +
"&Signature=" + urlSafeSignature + "&Key-Pair-Id=" + keyPairId;
return signedUrl;
}
/// <summary>
/// Generate a policy document that describes custom access permissions to
/// apply via a private distribution's signed URL.
/// </summary>
/// <param name="resourcePath">
/// An optional HTTP/S or RTMP resource path that restricts which
/// distribution and S3 objects will be accessible in a signed
/// URL. For standard distributions the resource URL will be
/// <tt>"http://" + distributionName + "/" + path</tt> (may
/// also include URL parameters. For distributions with the HTTPS
/// required protocol, the resource URL must start with
/// <tt>"https://"</tt>. RTMP resources do not take the form of a
/// URL, and instead the resource path is nothing but the stream's
/// name. The '*' and '?' characters can be used as a wildcards to
/// allow multi-character or single-character matches
/// respectively:
/// <ul>
/// <li><tt>*</tt> : All distributions/objects will be accessible</li>
/// <li><tt>a1b2c3d4e5f6g7.cloudfront.net/*</tt> : All objects
/// within the distribution a1b2c3d4e5f6g7 will be accessible</li>
/// <li><tt>a1b2c3d4e5f6g7.cloudfront.net/path/to/object.txt</tt>
/// : Only the S3 object named <tt>path/to/object.txt</tt> in the
/// distribution a1b2c3d4e5f6g7 will be accessible.</li>
/// </ul>
/// If this parameter is null the policy will permit access to all
/// distributions and S3 objects associated with the certificate
/// keypair used to generate the signed URL.
/// </param>
/// <param name="expiresOn">The time and date when the signed URL will expire.</param>
/// <param name="limitToIpAddressCIDR">An optional range of client IP addresses that will be allowed
/// to access the distribution, specified as a CIDR range. If
/// null or empty any client will be permitted.</param>
/// <param name="activeFrom">An optional UTC time and date when the signed URL will become
/// active. A value of DateTime.MinValue (the default value of DateTime) is ignored.
/// </param>
/// <returns>A policy document describing the access permission to apply when
/// generating a signed URL.</returns>
public static string BuildPolicyForSignedUrl(string resourcePath,
DateTime expiresOn,
string limitToIpAddressCIDR,
DateTime activeFrom)
{
// Reference:
// http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html#private-content-custom-policy-statement
// Validate if activeFrom (time at which the URL will be active)
// is less than expiresOn (time at which the URL will expire)
if (activeFrom > expiresOn)
{
throw new AmazonClientException("The parameter activeFrom (time at which the URL will be active)" +
"must be less than expiresOn (time at which the URL will expire).");
}
if (resourcePath == null)
{
resourcePath = "*";
}
string policy = "{\"Statement\": [{"
+ "\"Resource\":\""
+ resourcePath
+ "\""
+ ",\"Condition\":{"
+ "\"DateLessThan\":{\"AWS:EpochTime\":"
+ AWSSDKUtils.ConvertToUnixEpochSecondsString(expiresOn.ToUniversalTime())
+ "}"
// omitting IpAddress parameter indicates any ip address access
+ (string.IsNullOrEmpty(limitToIpAddressCIDR)
? ""
: ",\"IpAddress\":{\"AWS:SourceIp\":\"" + limitToIpAddressCIDR + "\"}")
// Ignore epochDateGreaterThan if its value is DateTime.MinValue, the default value of DateTime.
+ (activeFrom > DateTime.MinValue ? ",\"DateGreaterThan\":{\"AWS:EpochTime\":"
+ AWSSDKUtils.ConvertToUnixEpochSecondsString(activeFrom.ToUniversalTime()) + "}"
: string.Empty)
+ "}}]}";
return policy;
}
/// <summary>
/// Generate a policy document that describes custom access permissions to
/// apply via a private distribution's signed URL.
/// </summary>
/// <param name="resourcePath">
/// An optional HTTP/S or RTMP resource path that restricts which
/// distribution and resource path will be accessible in a signed
/// URL. For standard distributions the resource URL will be
/// <tt>"http://" + distributionName + "/" + path</tt> (may
/// also include URL parameters. For distributions with the HTTPS
/// required protocol, the resource URL must start with
/// <tt>"https://"</tt>. RTMP resources do not take the form of a
/// URL, and instead the resource path is nothing but the stream's
/// name. The '*' and '?' characters can be used as a wildcards to
/// allow multi-character or single-character matches
/// respectively:
/// <ul>
/// <li><tt>*</tt> : All distributions/objects will be accessible</li>
/// <li><tt>a1b2c3d4e5f6g7.cloudfront.net/*</tt> : All objects
/// within the distribution a1b2c3d4e5f6g7 will be accessible</li>
/// <li><tt>a1b2c3d4e5f6g7.cloudfront.net/path/to/object.txt</tt>
/// : Only the resource named <tt>path/to/object.txt</tt> in the
/// distribution a1b2c3d4e5f6g7 will be accessible.</li>
/// </ul>
/// If this parameter is null the policy will permit access to all
/// distributions and resource path associated with the certificate
/// keypair used to generate the signed URL.
/// </param>
/// <param name="expiresOn">The time and date when the signed URL will expire.</param>
/// <param name="limitToIpAddressCIDR">An optional range of client IP addresses that will be allowed
/// to access the distribution, specified as a CIDR range. If null, or empty, any client will
/// be permitted.</param>
/// <returns>A policy document describing the access permission to apply when
/// generating a signed URL.</returns>
public static string BuildPolicyForSignedUrl(string resourcePath,
DateTime expiresOn,
string limitToIpAddressCIDR)
{
return BuildPolicyForSignedUrl(resourcePath, expiresOn,
limitToIpAddressCIDR, DateTime.MinValue);
}
/// <summary>
/// Converts the given data to be safe for use in signed URLs for a private
/// distribution by using specialized Base64 encoding.
/// </summary>
internal static string MakeBytesUrlSafe(byte[] bytes)
{
return Convert.ToBase64String(bytes).Replace('+', '-').Replace('=', '_').Replace('/', '~');
}
/// <summary>
/// Converts the given string to be safe for use in signed URLs for a private distribution.
/// </summary>
internal static String MakeStringUrlSafe(string str)
{
return MakeBytesUrlSafe(UTF8Encoding.UTF8.GetBytes(str));
}
/// <summary>
/// Returns the resource path for the given distribution, object, and protocol.
/// </summary>
private static string GenerateResourcePath(Protocol protocol,
string distributionDomain,
string path)
{
if (protocol == Protocol.http || protocol == Protocol.https)
{
return protocol.ToString() + "://" + distributionDomain + "/" + path;
}
else
{
return path;
}
}
/// <summary>
/// Signs the data given with the private key given, using the SHA1withRSA
/// algorithm provided by bouncy castle.
/// </summary>
internal static byte[] SignWithSha1RSA(byte[] dataToSign, RSAParameters rsaParameters)
{
using (SHA1 cryptoSHA1 = GetSHA1Provider())
{
var providerRSA = RSA.Create();
providerRSA.ImportParameters(rsaParameters);
byte[] hashedData = cryptoSHA1.ComputeHash(dataToSign);
return GetRSAPKCS1SignatureFromSHA1(hashedData, providerRSA);
}
}
internal static RSAParameters ConvertPEMToRSAParameters(TextReader privateKeyReader)
{
RSAParameters rsaParams;
try
{
rsaParams = new PemReader(privateKeyReader).ReadPrivatekey();
}
catch (Exception e)
{
throw new AmazonClientException("Invalid RSA Private Key", e);
}
return rsaParams;
}
private static SHA1 GetSHA1Provider()
{
#if NETSTANDARD
return SHA1.Create();
#else
return new SHA1CryptoServiceProvider();
#endif
}
private static byte[] GetRSAPKCS1SignatureFromSHA1(byte[] hashedData, RSA providerRSA)
{
// Format the RSACryptoServiceProvider and create the signature.
#if NETSTANDARD
return providerRSA.SignHash(hashedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
#else
RSAPKCS1SignatureFormatter rsaFormatter = new RSAPKCS1SignatureFormatter(providerRSA);
rsaFormatter.SetHashAlgorithm("SHA1");
return rsaFormatter.CreateSignature(hashedData);
#endif
}
}
}