Can someone please help me convert the following two lines of python to C#.
hash = hmac.new(secret, data, digestmod = hashlib.sha1)
key = hash.hexdigest()[:8]
The rest looks like this if you're intersted:
#!/usr/bin/env python
import hmac
import hashlib
secret = 'mySecret'
data = 'myData'
hash = hmac.new(secret, data, digestmod = hashlib.sha1)
key = hash.hexdigest()[:8]
print key
Thanks
You could use the HMACSHA1 class to compute the hash:
class Program
{
static void Main()
{
var secret = "secret";
var data = "data";
var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(secret));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
Console.WriteLine(BitConverter.ToString(hash));
}
}
Related
I am trying to create a sha256 signature using a RSA Private Key but I am getting a 401 "Could not authenticate in-request, auth signature : Signature verification failed: affil-product, version: 2.0.0, env: prod
I think the issue is to do whit how it get my .pem file. I have read the Microsoft documentation and the provided Walmart example. I am following this guide. I created a non password protected key pair and uploaded the public key to Walmart. I then added my consumer ID and key version to appsettings.json {"Settings": {"consumerID": "e2ca6a2f-56f2-4465-88b3-273573b1e0c9","keyVer": "4"}}.
I am then getting this data in program.cs via the following code.
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();
// Get values from the config given their key and their target type.
Settings settings = config.GetRequiredSection("Settings").Get<Settings>();
I then instantiate Walmart affiliate object allowing us to use the methods needed to access and read Walmart api
WalMartAfilAPI wallMartAfilAPI = new WalMartAfilAPI();
From there I Create a RSACryptoServiceProvider object and import the .pem and export the parameter.
RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();
var rsaPem = File.ReadAllText("D:\\Users\\Adam\\source\\repos\\DealsBot\\DealsBot\\DealsBot\\wallmartAfill\\WM_IO_private_key.pem");
//now we instantiate the RSA object
var rsa = RSA.Create();
//replace the private key with our .pem
rsa.ImportFromPem(rsaPem);
//Export the key information to an RSAParameters object.
// You must pass true to export the private key for signing.
// However, you do not need to export the private key
// for verification.
RSAParameters Key = rsa.ExportParameters(true);
From here I get the time stamp and call methods from the Walmart Affiliate object.
//Get current im in unix epoch milliseconds
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
var time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
Console.WriteLine(time);
byte[] conicData = wallMartAfilAPI.Canonicalize(settings.KeyVer, settings.ConsumerID, time);
byte[] signedData = wallMartAfilAPI.HashAndSignBytes(conicData, Key);
if (wallMartAfilAPI.VerifySignedHash(conicData, signedData, Key))
{
Console.WriteLine("The data was verified");
;
Console.WriteLine(Convert.ToBase64String(signedData));
}
else
{
Here is the WalMartAfilAPI class
namespace DealsBot.wallmartAfill
{
public class WalMartAfilAPI
{
public byte[] Canonicalize(string version, string consumerId, string timestamp)
{
ASCIIEncoding ByteConverter = new ASCIIEncoding();
// Follow after the java code, which just orders the keys/values.
StringBuilder keyBuilder = new StringBuilder();
StringBuilder valueBuilder = new StringBuilder();
SortedDictionary<string, string> dictionary = new SortedDictionary<string, string>() { { "WM_CONSUMER.ID", consumerId }, { "WM_CONSUMER.INTIMESTAMP", timestamp }, { "WM_SEC.KEY_VERSION", version } };
foreach (string key in dictionary.Keys)
{
keyBuilder.Append($"{key.Trim()};");
valueBuilder.AppendLine($"{dictionary[key].Trim()}");
}
string[] conHeader = { keyBuilder.ToString(), valueBuilder.ToString() };
byte[] originalData = ByteConverter.GetBytes(conHeader[1]);
return originalData;
}
public byte[] HashAndSignBytes(byte[] DataToSign, RSAParameters Key)
{
try
{
// Create a new instance of RSACryptoServiceProvider using the
// key from RSAParameters.
RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();
RSAalg.ImportParameters(Key);
// Hash and sign the data. Pass a new instance of SHA256
// to specify the hashing algorithm.
return RSAalg.SignData(DataToSign, SHA256.Create());
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
public bool VerifySignedHash(byte[] DataToVerify, byte[] SignedData, RSAParameters Key)
{
try
{
// Create a new instance of RSACryptoServiceProvider using the
// key from RSAParameters.
RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();
RSAalg.ImportParameters(Key);
// Verify the data using the signature. Pass a new instance of SHA256
// to specify the hashing algorithm.
return RSAalg.VerifyData(DataToVerify, SHA256.Create(), SignedData);
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return false;
}
}
}
}
As of today, auth signature code is available in Java (https://www.walmart.io/docs/affiliate/onboarding-guide)
The idea we provided sample code to help the customers to implement the logic at customer end by referring it
You can implement the logic in(C# .NET, Python, PHP or JS) in such a way that whenever your system invoking Walmart APIs, generate the signature on the fly and pass as input parameter
This is how all of customers implemented and consuming our APIs
Pls refer the below documentation for complete.
https://walmart.io/docs/affiliate/quick-start-guide
https://www.walmart.io/docs/affiliate/onboarding-guide
Regards,
Firdos
IO Support
What will be analog of this code in PHP? I am not able to port this piece of code on PHP.
internal void GenerateKeyPair()
{
ecKey = new ECKey();
GeneratedPublicKey = new ECPublicKey()
{
X = ecKey.X,
Y = ecKey.Y,
CurveOId = ecKey.CurveOId
};
}
openssl_pkey_new() can generate a private key, see the Documentation for an example with private/public key usage.
I have the following code in ruby and C# to generate and verify RSA signature.
Ruby
Keys generation (in PEM format)
keys = OpenSSL::PKey::RSA.new 512
private_key = key.to_pem
public_key = key.public_key.to_pem
I store these keys in environment variables ENV["PRIVATE_KEY"] and ENV["PUBLIC_KEY"]
Generate signature
def generate_signature(token)
sign_hash = OpenSSL::Digest::SHA256.new
priv = OpenSSL::PKey::RSA.new(ENV["PRIVATE_KEY"])
signature = Base64.urlsafe_encode64(priv.sign(sign_hash, token))
signature.gsub!(/\n/, '')
end
Verify signature
def verify_signature(signature, token)
verify_hash = OpenSSL::Digest::SHA256.new
pub = OpenSSL::PKey::RSA.new(ENV["PUBLIC_KEY"])
pub.verify(verify_hash, Base64.urlsafe_decode64(signature), token)
end
given these methods, the following code returns true, so verification is succesful.
signature = generate_signature("string")
puts verify_signature(signature, "string")
C#
In C# I don't need to generate keys, I just need to verify signature, generated previously in ruby. Since System.Security.Cryptography doesn't work with PEM keys out of the box, I converted PEM key to XML format (using online converter)
Here is verification code, which returns false, so verification is unsuccesfull.
public const string publicKey = #"Public key in XML format";
public static bool Verify(string nonce, string signature)
{
RSACryptoServiceProvider RSAVerifier = new RSACryptoServiceProvider();
RSAVerifier.FromXmlString(publicKey);
signature = Base64Decode(signature);
byte[] SignatureBytes = Encoding.UTF8.GetBytes(signature);
byte[] VerifyFileData = Encoding.UTF8.GetBytes(nonce);
bool isValidSignature = RSAVerifier.VerifyData(VerifyFileData, CryptoConfig.MapNameToOID("SHA256"), SignatureBytes);
return isValidSignature;
}
Where Base64Decode is my custom method to replicate Base64.urlsafe_decode64 in ruby
public static string Base64Decode(string base64EncodedData)
{
byte[] base64EncodedBytes = Convert.FromBase64String(base64EncodedData.Replace('-', '+').Replace('_', '/'));
return Encoding.UTF8.GetString(base64EncodedBytes);
}
I need to decrypt some data in Flex that is encrypted in C# and written to a file.
I settled on blowfish for simplicity's sake using the as3crypto As3 library and Bruce Schneier C# library.
AS3 as3crypto link
Bruce Schneier C# blowfish link
I can get a short string to encrypt in C# and decrypt in Flex fine
however longer strings just fail to produce results and I do not know what I am missing?
C#:
string reportstring = "watson?";
BlowFish b = new BlowFish("04B915BA43FEB5B6");
string cipherText = b.Encrypt_ECB(reportstring);
String plainText = b.Decrypt_ECB(cipherText);
AS3:
var txt:String = "watson?";
var key:ByteArray = Hex.toArray("04B915BA43FEB5B6");
var blowfish:BlowFishKey = new BlowFishKey(key);
var dataBytes:ByteArray = new ByteArray();
dataBytes=Hex.toArray(Hex.fromString(txt));
blowfish.encrypt(dataBytes);
blowfish.decrypt(dataBytes);
Update, some samples
working
encrypt string = "watson?"
C# produces: 1514ea36fecfd5f5
AS3 produces: 1514ea36fecfd5f5
not working
encrypt string = "whats up watson?"
C# produces: 3ea9808a4b9f74aaa8e54fe682947673
AS3 produces: 3ea9808a4b9f74aa20776174736f6e3f
which is very similar but not matching
if I decrypt the AS3 cipher in C# I get :
whats up?`r???
if I decrypt the C# cipher in AS3 I get :
whats up¨åO悔vs
The AS3 code seems to be incorrect. Working example code:
import com.hurlant.util.Hex;
import com.hurlant.util.Base64;
import com.hurlant.crypto.Crypto;
import flash.utils.ByteArray;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.NullPad;
import com.hurlant.crypto.symmetric.BlowFishKey;
function encrypt($text:String, $cryptKey:ByteArray):String
{
var iPad:IPad = new NullPad();
var crypt = Crypto.getCipher('blowfish-ecb',$cryptKey,iPad);
var cryptText:ByteArray = new ByteArray();
cryptText.writeUTFBytes( $text );
crypt.encrypt( cryptText );
trace( Hex.fromArray( cryptText ) );
return null;
}
var txt:String = "whats up watson?";
var key:ByteArray = Hex.toArray("04B915BA43FEB5B6");
encrypt(txt, key);
Answer to "how do I decrypt the string afterwards":
var encodedtxt:String = Hex.fromArray(cryptText);
cryptText = Hex.toArray(encodedtxt);
crypt.decrypt(cryptText);
package
{
import com.hurlant.crypto.Crypto;
import com.hurlant.crypto.prng.Random;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.util.Base64;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
import mx.utils.Base64Decoder;
import mx.utils.Base64Encoder;
public class EncryptionManager
{
public function EncryptionManager()
{
}
public function enCrypt(data:String, keyStr:String):String
{
var key:ByteArray;
var fileBytes:ByteArray = Hex.toArray(Hex.fromString(data));
key = Hex.toArray(Hex.fromString(keyStr));
var aes:ICipher = Crypto.getCipher("blowfish-ecb", key, Crypto.getPad("pkcs5"));
aes.encrypt(fileBytes);
var enc:Base64Encoder = new Base64Encoder();
enc.encodeBytes(fileBytes);
var result:String = enc.flush();
return result;
}
public function deCrypt(data:String, keyStr:String):String
{
var key:ByteArray;
var dec:Base64Decoder = new Base64Decoder();
dec.decode(data);
var fileBytes:ByteArray = dec.toByteArray();
key = Hex.toArray(Hex.fromString(keyStr));
var aes:ICipher = Crypto.getCipher("blowfish-ecb", key, Crypto.getPad("pkcs5"));
aes.decrypt(fileBytes);
return fileBytes.toString();
}
}
}
Try out this Class that might solve your problem.
I am trying co import a .pem key into c#, and I've found a library, which does that: BouncyCastle
I've created a code, which loads public key and is supposed to load the data into DSACryptoServiceProvider:
DSA dsa;
using (StreamReader rdr = new StreamReader(#"pubkey.pem"))
{
PemReader pr = new PemReader(rdr);
DsaPublicKeyParameters o = pr.ReadObject() as DsaPublicKeyParameters;
CspParameters prm = new CspParameters(13);
prm.Flags = System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore;
//o.Parameters.
dsa = new DSACryptoServiceProvider(prm);
DSAParameters dp = new DSAParameters();
dp.G = o.Parameters.G.ToByteArray();
dp.P = o.Parameters.P.ToByteArray();
dp.Q = o.Parameters.Q.ToByteArray();
dp.Y = o.Y.ToByteArray();
if (o.Parameters.ValidationParameters != null)
{
dp.Counter = o.Parameters.ValidationParameters.Counter;
dp.Seed = o.Parameters.ValidationParameters.GetSeed();
}
//todo: missing: J, X?
dsa.ImportParameters(dp);
}
it crashes on dsa.ImportParameters(dp); with following exception: Cryptographic exception:bad data.
What should I change for this to work?
You need to use the ToByteArrayUnsigned method instead of plain ToByteArray one as otherwise there are cases where the byte array representation ends up with a leading zero byte which breaks everything :)