C to Perl Translation HMAC SHA1 , data and secret key - c#

I want to convert the C code below into perl. Anyone know how to do this? Do you use hmac_sha1_hex($data, $key);? Do you use the digest:sha module? I want to sign some data with a key, but use perl instead of C.
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.Web;
namespace Amazon.Cba.Signature.Common
{
public class SignatureCalculator
{
public SignatureCalculator()
{
}
public String calculateRFC2104HMAC(String data, String key)
{
String result = null;
KeyedHashAlgorithm algorithm = new HMACSHA1();
Encoding encoding = new UTF8Encoding();
algorithm.Key = encoding.GetBytes(key);
result = Convert.ToBase64String(algorithm.ComputeHash(encoding.GetBytes(data.ToCharArray())));
return result;
}
}
}

I would do this like so:
use MIME::Base64 ();
use Digest::HMAC_SHA1 ();
my $result = MIME::Base64::encode_base64(
Digest::HMAC_SHA1::hmac_sha1( $data, $key ),
''
);
or if you want a url-safe base64 encoding:
my $result = MIME::Base64::encode_base64url(
Digest::HMAC_SHA1::hmac_sha1( $data, $key ),
);
though you can also use the separate Digest::HMAC and Digest::SHA modules together.

Related

How can I convert PrivateKeyCiphertextBlob or PrivateKeyPlaintext to string?

I'm attempting to use the KMS GenerateDataKeyPairAsync in order to get the public and private key out for testing (Once it works I will switch to the GenerateDataKeyPairWithoutPlaintextAsync).
The GenerateDataKeyPairResponse has three memory streams for the Public Key, Private Key Ciphertext and Private Key plaintext.
I can't seem to convert any of these memory streams to string so I can actually then use the keys.
The SDK docs (https://docs.aws.amazon.com/sdkfornet/v3/apidocs/Index.html) say it will be Base64 encoded if using the HTTP api, does the SDK use the HTTP api? I can't seem to tell.
I have tried using StreamReader.ReadToEnd() and using Encoding.ENCODING.FromString(stream.ToArray()) using all the encodings but I can't seem to get a reasonable value out.
Am I missing something important here?
Thanks
Adding the code:
# USING: AWSSDK.KeyManagementService VERSION: 3.5.0-beta
using System;
using System.IO;
using System.Threading.Tasks;
using Amazon;
using Amazon.KeyManagementService;
using Amazon.KeyManagementService.Model;
using Amazon.Runtime;
namespace ConsoleApp1
{
class Program
{
static async Task Main(string[] args)
{
var credentials = new BasicAWSCredentials("AccessKey", "SecretKey");
var kmsClient = new AmazonKeyManagementServiceClient(credentials, RegionEndpoint.EUCentral1);
const string keyId = "CMKKey";
var dataKeyRequest = new GenerateDataKeyPairRequest
{
KeyId = keyId,
KeyPairSpec = DataKeyPairSpec.RSA_2048
};
var dataKeyPairResponse = await kmsClient.GenerateDataKeyPairAsync(dataKeyRequest);
var publicKeyStream = dataKeyPairResponse.PublicKey;
var privateKeyStream = dataKeyPairResponse.PrivateKeyPlaintext;
var publicReader = new StreamReader( publicKeyStream );
var publicKey = publicReader.ReadToEnd();
var privateReader = new StreamReader( privateKeyStream );
var privateKey = privateReader.ReadToEnd();
Console.WriteLine(publicKey);
Console.WriteLine(privateKey);
}
}
}
I think I have found a bug in the AWS library. Pretty deep in the call stack there is a DecodefromBase64 call but I don't think the string it is decoding is actually in Base64. Therefore you end up with a string that is actually a decoded normal string. If you encode the string with base64 it returns the correct string.
The following code will fix your issue... However, I will contact the team that works on this library and try to get it fixed. If it's fixed at the library level this code will stop working. So please use with caution/wait for an official fix.
var dataKeyPairResponse = await kmsClient.GenerateDataKeyPairAsync(dataKeyRequest);
var privateKeyBytes = dataKeyPairResponse.PrivateKeyPlaintext.ToArray();
var privateKey = Convert.ToBase64String(privateKeyBytes);
var publicKeyBytes = dataKeyPairResponse.PublicKey.ToArray();
var publicKey = Convert.ToBase64String(publicKeyBytes);
Console.Write(privateKey);
Console.Write(publicKey);

How can I get an SHA-256 certificate thumbprint?

How can I get the SHA-256 thumbprint of a certificate?
SHA-256 certificates have two thumbprint, and I am able to retrieve the primary thumbprint, but not SHA-256.
If you want to get a certificate's SHA-256 thumbprint, you have to do some manual work. The built-in Thumbprint property is SHA-1 only.
You have to use a SHA-256 class and compute the hash over the certificate's content:
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace MyNamespace {
class MyClass {
public static String GetSha2Thumbprint(X509Certificate2 cert) {
Byte[] hashBytes;
using (var hasher = new SHA256Managed()) {
hashBytes = hasher.ComputeHash(cert.RawData);
}
return hashBytes.Aggregate(String.Empty, (str, hashByte) => str + hashByte.ToString("x2"));
}
}
}
And you convert this code to an extension method if necessary.
Use:
public static String GetSha2Thumbprint(X509Certificate2 cert)
{
Byte[] hashBytes;
using (var hasher = new SHA256Managed())
{
hashBytes = hasher.ComputeHash(cert.RawData);
}
string result = BitConverter.ToString(hashBytes)
// This will remove all the dashes in between each two characters
.Replace("-", string.Empty).ToLower();
return result;
}
After getting the Hashbytes, you have to do the bit convertion.
This post also helped me: Hashing text with SHA-256 in Windows Forms

C# RSA Decryption using Bouncy Castle

I have been given a Base64 Encoded encrypted string, which was encrypted in Java using Bouncy Castle. Example Java snippet below:
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key.getPublic());
byte[] encryptedText = cipher.doFinal("xxxxx|xxxxx".getBytes("UTF-8"));
String encodedText = new BASE64Encoder().encode(encryptedText);
I need to decrypt the resulting string using Bouncy Castle, but in C#
I have been given a code snippet on how to do this in Java, but I can't convert this for C# (reasons is we are building a .net site, and is going to be an iFrame within a Java site. The Java site is going to passing in the RSA Encrypted string to the .NET site). Example Java code to decrypt below:
Cipher cipherDec = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipherDec.init(Cipher.DECRYPT_MODE, key.getPrivate());
byte[] decodedText = new BASE64Decoder().decodeBuffer(encodedText);
byte[] decryptedText = cipherDec.doFinal(decodedText);
String finalValue = new String(decryptedText, "UTF-8");
I have downloaded the examples from http://www.bouncycastle.org/csharp/ but there doesn't seem to be an example of inputting a string value to get encrypted, and it then going though the encrypt/decrypt process.
I have been given values for modulus, public exponent, private expontent, prime P, prime q, prime exponent p, prime exponent q and crt coefficient.
I have seen that I can use the following:
IAsymmetricBlockCipher signer = new Pkcs1Encoding(new RsaEngine());
signer.Init(true, pubParameters);
But the signer object doesn't seem to have the same methods as the Java examples above.
Only method I can use is
ProcessBlock(byte[] inbuf, int inOff, int inLen);
But I can't see how to use this in my context.
Any help here would be most appreciated.
To Help others, the final code to convert is as follows:
RsaKeyParameters privParameters = new RsaPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef);
RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod, pubExp);
IAsymmetricBlockCipher eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(false, privParameters);
byte[] encdata = System.Convert.FromBase64String("{the enc string}");
encdata = eng.ProcessBlock(encdata, 0, encdata.Length);
string result = Encoding.UTF8.GetString(encdata);
mod, pubExp etc etc are all BigInteger values:
static BigInteger mod = new BigInteger("big int value");
The Following using directives are required:
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Math;
Which can be obtained from the bouncycastle site. http://www.bouncycastle.org/csharp/
Have you tried converting the base 64 string to a byte array and then using the process block method? There may be more to it than that but it's definitely the first step I would take.
Here's an example of how to do this: http://msdn.microsoft.com/en-us/library/system.convert.frombase64string.aspx
I'm not sure I understand why you must use Bouncycastle. The following small code snippet shows and RSA encryption/decryption example using only .NET classes:
using System;
using System.Text;
using System.Security.Cryptography;
namespace RsaForDotNet
{
class Program
{
static void Main(string[] args)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512);
var encrypted_msg = rsa.Encrypt(Encoding.UTF8.GetBytes("Secret Data"), false);
var encoded_msg = Convert.ToBase64String(encrypted_msg);
Console.WriteLine(encoded_msg);
var decoded_msg = Convert.FromBase64String(encoded_msg);
var decrypted_msg = Encoding.UTF8.GetString(rsa.Decrypt(decoded_msg, false));
Console.WriteLine(decrypted_msg);
}
}
}

Cannot validate the signature with X509Certificate2

I am trying to use a self signed certificate to sign a string and then verify that the string is signed correctly.
This is how I create my self signed certificate:
makecert -r -n "CN=AuthCert2" -ss my -a sha1 -pe
After this I export the certificate to a pfx file and try to run the following code:
using System;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Net;
using System.Net.Security;
[TestClass]
public class TestSign
{
[TestMethod]
public void TestSignAndVerify()
{
string toSignString = "This is my string to sign";
byte[] data = UnicodeEncoding.UTF8.GetBytes(toSignString);
SHA1Managed sha1 = new SHA1Managed();
byte[] hash = sha1.ComputeHash(data);
X509Certificate2 signCert = new X509Certificate2("authcert2.pfx", "authpass");
var csp = (RSACryptoServiceProvider)signCert.PrivateKey;
byte[] signedData = csp.SignData(hash, CryptoConfig.MapNameToOID("SHA1"));
RSACryptoServiceProvider csp2 = (RSACryptoServiceProvider)signCert.PublicKey.Key;
bool result = csp2.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), signedData);
}
}
Yet I am always getting result as false. I am sure I am missing something very basic here. Any idea what is going on or how I can debug the problem?
thanks,
There are two things wrong within the code. First of all, the SignData computation already includes calculating the hash (no need to do it yourself) and the second is that you are using VerifyHash instead of VerifyData.

Trying to hash a password

Note: I will not be using salts. Thanks for your advice though!
I'm testing how to hash a password using SHA1 and can't seem to wrap my head around it. My database column is Password char(40) not null.
Here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;
namespace Consumer
{
class Program
{
static void Main(string[] args)
{
string password = "Mypassword";
byte[] data password.tobytearray()???
byte[] result;
SHA1 sha = new SHA1CryptoServiceProvider();
// This is one implementation of the abstract class SHA1.
result = sha.ComputeHash(data);
Console.WriteLine(result.ToString());
Console.ReadLine();
}
}
}
It sounds like you're trying to convert a string into a byte[]. This is done by using one of the Encoding classes.
byte[] data = System.Text.Encoding.Unicode.GetBytes(password);
byte[] data = System.Text.Encoding.ASCII.GetBytes(password);
I'm not sure which is most appropriate for your scenario but I would use Unicode unless I had a specific reason to do otherwise.
To convert a string to a Byte[], use the Encoding class.
Also, result is a Byte[], which doesn't override ToString().
To get a string representation of the byte array, you can call BitConverter.ToString or Convert.ToBase64String.
In a database, you should store the raw byte array directly.
So your correct program would be something like
static void Main(string[] args)
{
string password = "Mypassword";
byte[] data = System.Text.Encoding.ASCII.GetBytes(password);
//or byte[] data = System.Text.Encoding.Unicode.GetBytes(password);
byte[] result;
SHA1 sha = new SHA1CryptoServiceProvider();
// This is one implementation of the abstract class SHA1.
result = sha.ComputeHash(data);
Console.WriteLine(Convert.ToBase64String(result));
Console.ReadLine();
}

Categories