Issue passing private key and public key? - c#

I need to pass the public key and private key in string format for encryption and decryption in pgp. I've generated the keys like this but I am not able to use those. So can anyone tell me how to get the public key and private key in string format from this. And also the rsakeygenerator has not given the passphrase for private key. So where do I get passphrase for private key?
private void button2_Click(object sender, EventArgs e)
{
// keyPair = createASymRandomCipher();
//CipherPublicKey publicKey = getCipherPublicKey(keyPair);
AsymmetricCipherKeyPair keyPair = createASymRandomCipher();
Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters pubkey = (Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)keyPair.Public;
Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters privkey = (Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters)keyPair.Private;
CipherPublicKey pbkey = getCipherPublicKey(pubkey);
CipherPrivateKey prvkey = getCipherPrivateKey(privkey);
}
private static AsymmetricCipherKeyPair createASymRandomCipher()
{
RsaKeyPairGenerator r = new RsaKeyPairGenerator();
r.Init(new KeyGenerationParameters(new SecureRandom(),
1024));
AsymmetricCipherKeyPair keys = r.GenerateKeyPair();
return keys;
}
[Serializable]
private struct CipherPrivateKey
{
public byte[] modulus;
public byte[] publicExponent;
public byte[] privateExponent;
public byte[] p;
public byte[] q;
public byte[] dP;
public byte[] dQ;
public byte[] qInv;
}
[Serializable]
private struct CipherPublicKey
{
public bool isPrivate;
public byte[] modulus;
public byte[] exponent;
}
private static CipherPublicKey getCipherPublicKey(Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters cPublic)
{
CipherPublicKey cpub = new CipherPublicKey(); cpub.modulus = cPublic.Modulus.ToByteArray();
cpub.exponent = cPublic.Exponent.ToByteArray();
return cpub;
}
private static CipherPrivateKey getCipherPrivateKey(Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters cPrivate)
{
CipherPrivateKey cpri = new CipherPrivateKey();
cpri.dP = cPrivate.DP.ToByteArray();
cpri.dQ = cPrivate.DQ.ToByteArray();
cpri.modulus = cPrivate.Modulus.ToByteArray();
cpri.p = cPrivate.P.ToByteArray();
cpri.privateExponent = cPrivate.Exponent.ToByteArray();
cpri.publicExponent = cPrivate.PublicExponent.ToByteArray();
cpri.q = cPrivate.Q.ToByteArray();
cpri.qInv = cPrivate.QInv.ToByteArray();
return cpri;
}

You need to ask the user for the passphrase. The whole point of having a passphrase is that you won't be able to work out the private key without it, and only the user can supply it.
(I haven't looked at the rest of your code, not being familiar with the BouncyCastle API. I do question the wisdom of a mutable struct with lots of byte arrays though...)

The answer to just your converting question is to convert them to Base64Strings
If you want it in hex (so a user can enter it easier), you can use the System.Runtime.Remoting.Metadata.W3cXsd2001 namespace to get convert to/from a HEX rep. Here is an example in C#.
I will also say that there may be a security flaw in your though process, but I am not sure that I am qualified to address it. (See Jon's post)

Related

How to COSE sign CBOR binary document using C# .Net core?

How to COSE sign CBOR binary document using C# .Net core?
I've found there is NuGet Package Com.AugustCellars.COSE
But I'm new to this field and I can't find any examples, how to use it.
Finally I myself came up with working example
using Com.AugustCellars.COSE;
using PeterO.Cbor;
using System;
using System.Security.Cryptography.X509Certificates;
namespace Example
{
class CoseSignExampleClass
{
public void RunCoseSigningExample()
{
string exampleJson = "{\"name\":\"example\"}";
CBORObject exampleCbor = CBORObject.FromJSONString(exampleJson);
byte[] cborBytes = exampleCbor.EncodeToBytes();
// signedCbor now is COSE signed CBOR document
byte[] signedCbor = CoseSign(cborBytes);
// one can check verify signature with public key
bool validSignature = ValidateCoseSignature(signedCbor);
// one can get back document
byte[] extractedCborBytes = GetCoseContent(signedCbor);
PeterO.Cbor.CBORObject decodedCborData = PeterO.Cbor.CBORObject.DecodeFromBytes(extractedCborBytes);
string output = decodedCborData.ToString();
}
byte[] CoseSign(byte[] cborBytes)
{
OneKey signKeyPrivate = GetSignPrivateKey();
Sign1Message signMessage = new Sign1Message();
signMessage.AddAttribute(HeaderKeys.Algorithm, AlgorithmValues.ECDSA_256, Attributes.PROTECTED);
signMessage.SetContent(cborBytes);
signMessage.Sign(signKeyPrivate);
byte[] rgbMsg = signMessage.EncodeToBytes();
return rgbMsg;
}
static OneKey GetSignPrivateKey()
{
/*
* privateKeyString is PKCS8 key without starting and ending tags
* "-----BEGIN PRIVATE KEY-----"
* "-----END PRIVATE KEY-----"
*/
string privateKeyString = #"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgfK2MnqJPUzuSy2tB
t7kjH5OGeP8O38dkOMXmKNfVynuhRANCAASPTR2m+kV/3Xuxh8tjRxJn0v//Y/yS
Tl+LHlBowq7v+i6sGpJXEfPYbBc+tGZBL9MXX6WMV1I0QCMykqLyKwD3";
byte[] Pkcs8PrivateKey = Convert.FromBase64String(privateKeyString);
OneKey cnKeyPrivate = OneKey.FromPkcs8(Pkcs8PrivateKey);
return cnKeyPrivate;
}
byte[] GetCoseContent(byte[] coseDocument)
{
Sign1Message msg = (Sign1Message)Message.DecodeFromBytes(coseDocument, Tags.Sign1);
return msg.GetContent();
}
bool ValidateCoseSignature(byte[] coseDocument)
{
Sign1Message msg = (Sign1Message)Message.DecodeFromBytes(coseDocument, Tags.Sign1);
OneKey cnKeyPublic = GetSignPublicKey();
return msg.Validate(cnKeyPublic);
}
static OneKey GetSignPublicKey()
{
/*
* publicKeyString is Pem public cert without starting and ending tags
* "-----BEGIN CERTIFICATE-----"
* "-----END CERTIFICATE-----"
*/
string publicKeyString = #"MIICTzCCAfWgAwIBAgIUJgt2piBt1qKUVWqjs/bhkSTpbscwCgYIKoZIzj0EAwIw
ZDELMAkGA1UEBhMCTFYxLTArBgNVBAoMJE5hY2lvbsOEwoFsYWlzIFZlc2Vsw4TC
q2JhcyBkaWVuZXN0czEMMAoGA1UECwwDVExTMRgwFgYDVQQDDA9UTFMgREdDIExW
IFRlc3QwHhcNMjEwNTE4MTA0OTA1WhcNMjMwNTE4MTA0OTA1WjBkMQswCQYDVQQG
EwJMVjEtMCsGA1UECgwkTmFjaW9uw4TCgWxhaXMgVmVzZWzDhMKrYmFzIGRpZW5l
c3RzMQwwCgYDVQQLDANUTFMxGDAWBgNVBAMMD1RMUyBER0MgTFYgVGVzdDBZMBMG
ByqGSM49AgEGCCqGSM49AwEHA0IABI9NHab6RX/de7GHy2NHEmfS//9j/JJOX4se
UGjCru/6LqwaklcR89hsFz60ZkEv0xdfpYxXUjRAIzKSovIrAPejgYQwgYEwDgYD
VR0PAQH/BAQDAgeAMB0GA1UdDgQWBBQO528ONBxapB+St9et1oYQySBhjjA3BgNV
HR8EMDAuMCygKqAohiZodHRwOi8vY3JsLm5wa2QubmwvQ1JMcy9OTEQtSGVhbHRo
LmNybDAXBgNVHSUEEDAOBgwrBgEEAQCON49lAQEwCgYIKoZIzj0EAwIDSAAwRQIg
Bc50+qIVI+IUQrUJQdYywW1PhNEyW5VxiT3HvGxyJaACIQD+ze+4r5GUcuWdNpPP
lFcSLRBj/MNpO6sl8h2Y5h/c8g==";
byte[] publicKeyData = Convert.FromBase64String(publicKeyString);
byte[] certData;
using (X509Certificate2 x509Cert = new X509Certificate2(publicKeyData))
certData = x509Cert.GetRawCertData();
OneKey keyPublic = OneKey.FromX509(certData);
return keyPublic;
}
}
}

C# / WPF RSA Doesn't Decrypt Text

I have a problem when I try to decrypt a string generated using RSA in C#. It Encrypts the strings well, but it throws an error when I try to decrypt the string using the private key:
Error occurred while decoding OAEP padding.
I tried changing the fOAEP parameter between true and false, changing the RSACryptoServiceProviders with 2048 as parameter and still doesn't work.
Project is a WPF App which generates 2 files with the keys, keys are loaded by the core.cs file.
Then keys are being loaded.
The example I taken only uses the public key to encrypt the string and only the private key to decrypt the string.
Core.cs File
// Keys are generated
public void GeneratePublicKey(string publicKeyFile) {
using (var rsa = new RSACryptoServiceProvider(2048)) {
rsa.PersistKeyInCsp = false;
if (File.Exists(publicKeyFile))
File.Delete(publicKeyFile);
//and the public key ...
var pubKey = rsa.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString; {
//we need some buffer
var sw = new System.IO.StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
}
File.WriteAllText(publicKeyFile, pubKeyString);
}
}
public void GeneratePrivateKey(string privateKeyFile) {
using (var rsa = new RSACryptoServiceProvider(2048)) {
rsa.PersistKeyInCsp = false;
if (File.Exists(privateKeyFile))
File.Delete(privateKeyFile);
//how to get the private key
var privKey = rsa.ExportParameters(true);
//converting the public key into a string representation
string privKeyString;
{
//we need some buffer
var sw = new System.IO.StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, privKey);
//get the string from the stream
privKeyString = sw.ToString();
}
File.WriteAllText(privateKeyFile, privKeyString);
}
}
//Si las llaves ya existen entonces NO Generar, solo leer la llave indicada (leer el texto de la ruta)
public RSAParameters ReadPublicKey(string publicKeyFile) {
//Leer
string pubKeyString = File.ReadAllText(publicKeyFile);
//Reconvertir
var sr = new System.IO.StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
return (RSAParameters)xs.Deserialize(sr);
}
public RSAParameters ReadPrivateKey(string privateKeyFile) {
//Leer
string privKeyString = File.ReadAllText(privateKeyFile);
//Reconvertir
var sr = new System.IO.StringReader(privKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
return (RSAParameters)xs.Deserialize(sr);
}
//Con la llave publica se encripta el texto
public string Encrypt(string publicKeyFile, string textToEncrypt) {
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(ReadPublicKey(publicKeyFile));
//for encryption, always handle bytes...
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(textToEncrypt);
//apply pkcs#1.5 padding and encrypt our data
var bytesCypherText = csp.Encrypt(bytesPlainTextData, true);
//we might want a string representation of our cypher text... base64 will do
Debug.WriteLine("Texto Encriptado: "+Convert.ToBase64String(bytesCypherText));
return Convert.ToBase64String(bytesCypherText);
}
/// <summary>
/// Con la llave Privada se Desencripta
/// </summary>
/// <param name="privateKeyFile"></param>
/// <param name="textToDecrypt"></param>
/// <returns></returns>
public string Decrypt(string privateKeyFile, string textToDecrypt) {
//first, get our bytes back from the base64 string ...
var bytesCypherText = Convert.FromBase64String(textToDecrypt);
//we want to decrypt, therefore we need a csp and load our private key
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(ReadPrivateKey(privateKeyFile));
//decrypt and strip pkcs#1.5 padding
var bytesPlainTextData = csp.Decrypt(bytesCypherText, true);
Debug.WriteLine("Desencriptado: "+
System.Text.Encoding.Unicode.GetString(bytesPlainTextData));
//get our original plainText back...
return System.Text.Encoding.Unicode.GetString(bytesPlainTextData);
}
MainWindow.cs
public partial class MainWindow : Window {
readonly RsaEnc _rs = new RsaEnc();
private string _publicKeyFile = "./public.cert";
private string _privateKeyFile = "./private.key";
public MainWindow() {
InitializeComponent();
}
private void GenerateBtn_Click(object sender, RoutedEventArgs e) {
_rs.GeneratePublicKey(_publicKeyFile);
_rs.GeneratePrivateKey(_privateKeyFile);
}
private void OpenPublic_Click(object sender, RoutedEventArgs e) {
OpenFileDialog fileDialog = new OpenFileDialog {
Multiselect = false, Filter = "Public |*.cert", DefaultExt = ".cert"
};
bool? dialogOk = fileDialog.ShowDialog();
if (dialogOk == true) {
string sFilenames = "";
foreach (string sFileName in fileDialog.FileNames) {
sFilenames += ";" + sFileName;
}
sFilenames = sFilenames.Substring(1);
_publicKeyFile = sFilenames;//Esto solo da la RUTA
Debug.WriteLine("public Cert: " + _publicKeyFile);
}
}
private void OpenPrivate_Click(object sender, RoutedEventArgs e) {
OpenFileDialog fileDialog = new OpenFileDialog
{
Multiselect = false, Filter = "Certificates |*.key", DefaultExt = ".key"
};
bool? dialogOk = fileDialog.ShowDialog();
if (dialogOk == true) {
string sFilenames = "";
foreach (string sFileName in fileDialog.FileNames) {
sFilenames += ";" + sFileName;
}
sFilenames = sFilenames.Substring(1);
_privateKeyFile = sFilenames; //Esto solo da la RUTA
Debug.WriteLine("private Key: " + _privateKeyFile);
}
}
private void EncryptBtn_Click(object sender, RoutedEventArgs e) {
_rs.Encrypt(_publicKeyFile, BoxToEncrypt.Text);
}
private void DecryptBtn_Click(object sender, RoutedEventArgs e) {
_rs.Decrypt(_privateKeyFile, BoxToDecrypt.Text);
}
}
First thing, WPF and Decryption are two different things. So, we have to concentrate only on the RSA encrypt/decrypt part.
In your code, you are trying to generate public/private keys using different methods. One single rsaprovider should export both parameters. I have provided a sample code for using RSA encryption/decryption. Please check below.
internal sealed class RSA
{
public static (string public_key, string private_key) getKeyPair()
{
try
{
var rsa_provider = new RSACryptoServiceProvider(1024);
return (rsa_provider.ToXmlString(false), rsa_provider.ToXmlString(true));
}
catch (Exception ex)
{
throw ex;
}
}
public static byte[] shroud_divulge(byte[] input_byte, string _key,bool is_shroud)
{
try
{
var rsa_provider = new RSACryptoServiceProvider();
rsa_provider.FromXmlString(_key);
var padding = RSAEncryptionPadding.OaepSHA256;
switch(is_shroud)
{
case true:
return rsa_provider.Encrypt(input_byte, padding);
case false:
return rsa_provider.Decrypt(input_byte, padding);
}
return null;
}
catch (Exception)
{
throw;
}
}
}
It has two simple methods and returns output using valuetuple(So add Valutuple nuget package).
The file saving and processing are done outside of the RSA logic. Shroud- Encryption, Divulge-Decryption. (Please excuse the naming conventions used, its as per our company standards).
We usually ship our publickey along with our WPF application.
For encryption (Shroud), we pass in the private key..
For decryption (Divulge) , we pass in the publich key..
RSA keys are always generated in pairs, a public and a private. These keys are created in the constructor of RSACryptoServiceProvider. Your code calls this constructor in both GeneratePublicKey and GeneratePrivateKey, therefore there will be two unrelated key-pairs generated.
You should be able to check this. When exporting parameters the public component is always included. If they are not identical that that would serve as confirmation.
The fix would be to generate the public and private key at the same time.

How do I detect if AsymmetricAlgorithm is a private key or a public key

Is there a simple way to check if a given AsymmetricAlgorithm is a private or a public key? Consider the following example:
private void SavePrivateKey(AsymmetricAlgorithm asymmetricAlgorithm)
{
// if (asymmetricAlgorithm.IsPrivateKey == false)
// throw new ArgumentException();
}
private void SavePrivateKeys()
{
var certificate = CreateCertificate();
var privateKey = RSACertificateExtensions.GetRSAPrivateKey(certificate);
var publicKey = RSACertificateExtensions.GetRSAPublicKey(certificate);
SavePrivateKey(privateKey);
SavePrivateKey(publicKey); // this should throw an exception
}
private X509Certificate2 CreateCertificate()
{
CngKeyCreationParameters keyParams = new CngKeyCreationParameters();
keyParams.KeyUsage = CngKeyUsages.Signing;
keyParams.Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider;
keyParams.ExportPolicy = CngExportPolicies.AllowExport | CngExportPolicies.AllowPlaintextExport;
keyParams.Parameters.Add(new CngProperty("Length", BitConverter.GetBytes(2048), CngPropertyOptions.None));
var cngKey = CngKey.Create(CngAlgorithm.Rsa, Guid.NewGuid().ToString(), keyParams);
var rsaKey = new RSACng(cngKey);
var req = new CertificateRequest("cn=mycert", rsaKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5));
return cert;
}
Here, both private and public keys have the same type - RSACng. In theory I can try to export key parameters and see if the public key fails to export the private key params. But then I would not know if the export failed because it is a public key, or because it is missing export policies or something else went wrong. Also the underlying key type may be different, it could be RSACng, RSACryptoServiceProvider, DSA etc.
The ToXmlString() method takes in the includePrivateParameters parameter. If that parameter is set, and the AsymmetricAlgorithm object does not include information about the private key, ToXmlString() will throw a CryptographicException exception:
private void SavePrivateKey(AsymmetricAlgorithm aa)
{
System.Console.Write("This is ");
try
{
aa.ToXmlString(true);
}
catch(CryptographicException ce)
{
System.Console.Write("not ");
}
System.Console.WriteLine("a private key");
}

How import and export RSAParameters keys to file without making a change to the keys in C#

I'm writing a digital signing program using C# and I use RSACryptoServiceProvider class that generates public and private keys and signatures depending on the file. If in the program, I check the signature with the public key, signature and file, it works correctly but If I save my keys to any format in the file, In other words, I will change their format and return to the first state It doesn't work. because I can not turn it into RSAParameters correctly. please guide me?
Simple example test to show the change:
var publicParams = rsaWrite.ExportParameters(false); // Generate the public key.
var testpublicParams = publicParams;
string st = Encoding.ASCII.GetString(publicParams.Modulus);
testpublicParams.Modulus = Encoding.ASCII.GetBytes(st);
if(publicParams.Modulus != testpublicParams.Modulus) {
Console.WriteLine("The key has been changed.");
}
You can get PublicKey as string format and save it on the other text file.
public static string PublicKey(string certSubject)
{
var my = new X509Store(StoreName.My, StoreLocation.LocalMachine);
my.Open(OpenFlags.ReadOnly);
RSACryptoServiceProvider csp = null;
byte[] publicKeyByte = null;
foreach (var cert in my.Certificates)
{
if (cert.Subject.Contains(certSubject))
{
csp = (RSACryptoServiceProvider)cert.PublicKey.Key;
publicKeyByte = cert.PublicKey.EncodedKeyValue.RawData;
}
}
if (csp == null)
{
throw new Exception("No valid cert was found");
}
var publicKey = new StringBuilder();
publicKey.AppendLine("-----BEGIN PUBLIC KEY-----");
publicKey.AppendLine(Convert.ToBase64String(publicKeyByte, Base64FormattingOptions.InsertLineBreaks));
publicKey.AppendLine("-----END PUBLIC KEY-----");
return publicKey.ToString();
}
This code has two problems:
The use of Encoding.ASCII.GetBytes is wrong because it might have a non-ASCII characters so we use the Convert.ToBase64String.
publicParams.Modulus is C# byte array so != probably not the right answer so we use SequenceEqual.
And the key will not change.
var rsaWrite = new RSACryptoServiceProvider();
var publicParams = rsaWrite.ExportParameters(false); // Generate the public key.
var testpublicParams = publicParams;
string st = Convert.ToBase64String(publicParams.Modulus);
testpublicParams.Modulus = Convert.FromBase64String(st);
if (!publicParams.Modulus.SequenceEqual(testpublicParams.Modulus))
{
Console.WriteLine("The key has been changed.");
}
else
{
Console.WriteLine("The key has not been changed. :D");
}

What should be the signing key for the AWS HTTP Post example?

I am trying to walk through the sample code using the values in the "Example: Browser-Based Upload using HTTP POST (Using AWS Signature Version 4)" page, but could not get the same signature value posted on the page.
The page does not show the value for the signing key. Does anybody know what it supposed to be? Thanks.
namespace TestAWSSignature
{
class Program
{
// Values from aws example page.
const string aKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
const string anID = "AKIAIOSFODNN7EXAMPLE";
const string aRegion = "us-east-1";
const string aService = "s3";
const string aBucket = "sigv4examplebucket";
const string HMACSHA256 = "HMACSHA256";
const string aDate = "20151229";
const string SCHEME = "AWS4";
const string ALGORITHM = "HMAC-SHA256";
const string TERMINATOR = "aws4_request";
static void Main(string[] args)
{
// Initial to value from aws example page.
string base64PolicyString = "eyAiZXhwaXJhdGlvbiI6ICIyMDE1LTEyLTMwVDEyOjAwOjAwLjAwMFoiLA0KICAiY29uZGl0aW9ucyI6IFsNCiAgICB7ImJ1Y2tldCI6ICJzaWd2NGV4YW1wbGVidWNrZXQifSwNCiAgICBbInN0YXJ0cy13aXRoIiwgIiRrZXkiLCAidXNlci91c2VyMS8iXSwNCiAgICB7ImFjbCI6ICJwdWJsaWMtcmVhZCJ9LA0KICAgIHsic3VjY2Vzc19hY3Rpb25fcmVkaXJlY3QiOiAiaHR0cDovL3NpZ3Y0ZXhhbXBsZWJ1Y2tldC5zMy5hbWF6b25hd3MuY29tL3N1Y2Nlc3NmdWxfdXBsb2FkLmh0bWwifSwNCiAgICBbInN0YXJ0cy13aXRoIiwgIiRDb250ZW50LVR5cGUiLCAiaW1hZ2UvIl0sDQogICAgeyJ4LWFtei1tZXRhLXV1aWQiOiAiMTQzNjUxMjM2NTEyNzQifSwNCiAgICB7IngtYW16LXNlcnZlci1zaWRlLWVuY3J5cHRpb24iOiAiQUVTMjU2In0sDQogICAgWyJzdGFydHMtd2l0aCIsICIkeC1hbXotbWV0YS10YWciLCAiIl0sDQoNCiAgICB7IngtYW16LWNyZWRlbnRpYWwiOiAiQUtJQUlPU0ZPRE5ON0VYQU1QTEUvMjAxNTEyMjkvdXMtZWFzdC0xL3MzL2F3czRfcmVxdWVzdCJ9LA0KICAgIHsieC1hbXotYWxnb3JpdGhtIjogIkFXUzQtSE1BQy1TSEEyNTYifSwNCiAgICB7IngtYW16LWRhdGUiOiAiMjAxNTEyMjlUMDAwMDAwWiIgfQ0KICBdDQp9";
byte[] policyStringBytes = Convert.FromBase64String(base64PolicyString);
// compute the signing key
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(HMACSHA256);
kha.Key = DeriveSigningKey(HMACSHA256, aKey, aRegion, aDate, aService);
Console.WriteLine(String.Format("Signing Key: {0}.\n", System.Convert.ToBase64String(kha.Key)));
// SigningKey value is: y87x6+rvyCzOZTC58KmuWYhGBl9cW64GdL1evEulLSg=
// Is this the correct value?
// Compute the signature.
byte[] signature = kha.ComputeHash(policyStringBytes);
string signatureString = ToHexString(signature, true);
Console.WriteLine(String.Format("Signature: {0}.\n", signatureString));
// The computed signature value is:
// 00e98ae3199cdbfeba701f9efa66510f23f0295ab6d6f4d14202f8ef2d11956c
// But according to the aws example page it should be:
// 8afdbf4008c03f22c2cd3cdb72e4afbb1f6a588f3255ac628749a66d7f09699e
Console.WriteLine("Done.");
}
// Functions below are straight from AWSSignatureV4-S3-Sample code.
/// Compute and return the multi-stage signing key for the request.
static byte[] DeriveSigningKey(string algorithm, string awsSecretAccessKey, string region, string date, string service)
{
const string ksecretPrefix = SCHEME;
char[] ksecret = null;
ksecret = (ksecretPrefix + awsSecretAccessKey).ToCharArray();
byte[] hashDate = ComputeKeyedHash(algorithm, Encoding.UTF8.GetBytes(ksecret), Encoding.UTF8.GetBytes(date));
byte[] hashRegion = ComputeKeyedHash(algorithm, hashDate, Encoding.UTF8.GetBytes(region));
byte[] hashService = ComputeKeyedHash(algorithm, hashRegion, Encoding.UTF8.GetBytes(service));
return ComputeKeyedHash(algorithm, hashService, Encoding.UTF8.GetBytes(TERMINATOR));
}
/// Compute and return the hash of a data blob using the specified algorithm and key
static byte[] ComputeKeyedHash(string algorithm, byte[] key, byte[] data)
{
var kha = KeyedHashAlgorithm.Create(algorithm);
kha.Key = key;
return kha.ComputeHash(data);
}
/// Helper to format a byte array into string
static string ToHexString(byte[] data, bool lowercase)
{
var sb = new StringBuilder();
for (var i = 0; i < data.Length; i++)
{
sb.Append(data[i].ToString(lowercase ? "x2" : "X2"));
}
return sb.ToString();
}
}
}

Categories