I am trying to use the Google Streetview Static API to get mass amounts of streetview images. I have a working API key and URL signing secret but I am having trouble with encoding the signature. No matter what I have tried I get the wrong signature and the url does not work. Any help would be appreciated.
Here is what I have done (the Encode method is not mine):
static void Main(string[] args)
{
Process.Start(GenerateURL(0, 0, "40.7488115", "-73.9855688", 1920, 1080, 90));
Console.ReadLine();
}
public static string GenerateURL(double heading, double pitch, string locationLat, string locationLong, int resX, int resY, int fov)
{
string universalURL = "size=" + resX + "x" + resY + "&location=" + locationLat + "," + locationLong + "&heading=" + heading + "&pitch=" + pitch + "&fov=" + fov + "&key=" + apiKey;
string getURL = "https://maps.googleapis.com/maps/api/streetview?" + universalURL;
string getSignature = "_maps_api_streetview?" + universalURL;
return getURL + "&signature=" + Encode(getSignature, signingKey);
}
public static string Encode(string input, string inputkey)
{
byte[] key = Encoding.ASCII.GetBytes(inputkey);
byte[] byteArray = Encoding.ASCII.GetBytes(input);
using (var myhmacsha1 = new HMACSHA1(key))
{
var hashArray = myhmacsha1.ComputeHash(byteArray);
return hashArray.Aggregate("", (s, e) => s + String.Format("{0:x2}", e), s => s);
}
}
The reason I use _ instead of / for getSignature is because here it says it needs to be replaced. I have already tried with / and it does not work.
Thanks for any help.
EDIT:
I have found the solution on the google website:
static void Main(string[] args)
{
Process.Start(GenerateURL(0, 0, "-26.235859", "28.077619", 500, 500, 90));
Console.ReadLine();
}
public static string GenerateURL(double heading, double pitch, string locationLat, string locationLong, int resX, int resY, int fov)
{
return Sign("https://maps.googleapis.com/maps/api/streetview?size=" + resX + "x" + resY + "&location=" + locationLat + "," + locationLong + "&heading=" + heading + "&pitch=" + pitch + "&fov=" + fov + "&key=" + apiKey, signingKey);
}
public static string Sign(string url, string keyString)
{
ASCIIEncoding encoding = new ASCIIEncoding();
// converting key to bytes will throw an exception, need to replace '-' and '_' characters first.
string usablePrivateKey = keyString.Replace("-", "+").Replace("_", "/");
byte[] privateKeyBytes = Convert.FromBase64String(usablePrivateKey);
Uri uri = new Uri(url);
byte[] encodedPathAndQueryBytes = encoding.GetBytes(uri.LocalPath + uri.Query);
// compute the hash
HMACSHA1 algorithm = new HMACSHA1(privateKeyBytes);
byte[] hash = algorithm.ComputeHash(encodedPathAndQueryBytes);
// convert the bytes to string and make url-safe by replacing '+' and '/' characters
string signature = Convert.ToBase64String(hash).Replace("+", "-").Replace("/", "_");
// Add the signature to the existing URI.
return uri.Scheme + "://" + uri.Host + uri.LocalPath + uri.Query + "&signature=" + signature;
}
Related
I have this code in C# which use it to generate a QR code base64 and want to decode the output into original TLV values as strings, for example in my code I am generating the QR code encode base64 and want to get back with original TLVs tags and store it in separate string per each value
using System;
namespace tlvgenerator
{
class Program
{
static void Main(string[] args)
{
string Name = GetHexString(1, Encoding.UTF8.GetBytes("Name")); //Tag1
string Serial = GetHexString(2, Encoding.UTF8.GetBytes("123456789123456789")); //Tag2
string dateTimeStr = GetHexString(3, Encoding.UTF8.GetBytes("2022-07-17T11:20:51Z")); //Tag3
string ModelNum = GetHexString(4, Encoding.UTF8.GetBytes("12356.123")); //Tag4
string PartNo = GetHexString(5, Encoding.UTF8.GetBytes("9782.45")); //Tag5
string SN = GetHexString(6, Encoding.UTF8.GetBytes("abcdef12345"));//Tag6
string Shelf = GetHexString(7, Encoding.UTF8.GetBytes("A2F345"));//Tag6
string Area = GetHexString(8, Convert.FromBase64String(Area)); //Tag7
string Building = GetHexString(9, Convert.FromBase64String(Building)); //Tag8
string decString = Name + Serial + dateTimeStr + ModelNum + PartNo + SN + Shelf + Area + Building;
string finalQR = HexToBase64(decString);
Console.WriteLine(finalQR);
}
static string GetHexString(int tagNo, byte[] tagValue)
{
string strTagNo = string.Format("0{0:X}", tagNo);
string tagNoVal = strTagNo.Substring(strTagNo.Length - 2, 2);
string strTagValueLength = string.Format("0{0:X}", tagValue.Length);
string tagValueLengthVal = strTagValueLength.Substring(strTagValueLength.Length - 2, 2);
return tagNoVal + tagValueLengthVal + BitConverter.ToString(tagValue).Replace("-", "");
}
static string gethexDec(Int32 TagValue)
{
string hxint = String.Format("0{0:X}", TagValue);
return hxint.Substring(hxint.Length - 2, 2);
}
public static string HexToBase64(string strInput)
{
try
{
var bytes = new byte[strInput.Length / 2];
for (var i = 0; i < bytes.Length; i++)
{
bytes[i] = Convert.ToByte(strInput.Substring(i * 2, 2), 16);
}
return Convert.ToBase64String(bytes);
}
catch (Exception)
{
return "-1";
}
}
}
}
I need to convert an MAc Address - 88:E9:FE:A8:1F:2F
for this format '0xA8FEE988 0x00002F1F 0x00000000 0x00000000'
I did this code below, but it is not elegant. Someone can help me?
string txtMacAddr = "88:E9:FE:A8:1F:2F";
string cmdMAc = "";
var macReverso = Util.Mac_Reverso(txtMacAddr.Replace(":",""));
string[] macRev = new string[4];
macRev[0] = $"0x{macReverso.Substring(4, 8)}";
macRev[1] = $"0x0000{macReverso.Substring(0, 4)}";
macRev[2] = "0x00000000";
macRev[3] = "0x00000000";
foreach (var xl in macRev)
{
cmdMAc += xl + " ";
}
Logger.WriteLine(cmdMAc); //op '0xA8FEE988 0x00002F1F 0x00000000 0x00000000'
public static string Mac_Reverso(string macAddress)
{
string macRevertido = string.Empty;
string s = macAddress.Replace("0x", "");//'0xA8FEE988 0x00002F1F 0x00000000 0x00000000'
string[] macLista = s.Split(' ');
foreach (var mac in macLista)
{
for (var i = mac.Length; i > 0; i -= 2)
{
macRevertido += mac.Substring(i - 2, 2);
if (macRevertido.Length == 12)
{
return macRevertido; //2F1FA8FEE988
}
}
}
return macRevertido;
}
What do you mean by not elegant? The following code will get the same result and in my opinion its easier to read. The first option is to show it can be done just by using char references, if the mac address will always look the same. The second result is easier to read in my head.
Note: If 88 was changed to 08 and the zero was omitted for some reason, the the following input would break both of them: 8:E9:FE:A8:1F:2F Does this case matter to you?
Is the output you included in your post what you are trying to get? What exactly are you trying to do?
//Reference each char individually. Could break if char position changes.
string mac = "88:E9:FE:A8:1F:2F";
string reverseMac = "0x" + mac[9] + mac[10] + mac[6] + mac[7] + mac[3] + mac[4] + mac[0] + mac[1] + " 0x0000" + mac[15] + mac[16] + mac[12] + mac[13] + " 0x00000000 0x00000000";
//Output:0xA8FEE988 0x00002F1F 0x00000000 0x00000000
//Better Option: Split by the ':' delimiter and reference each group of chars.
string[] macChars = mac.Split(":"); //Breaks into groups
string newMac2 = "0x" + macChars[3] + macChars[2] + macChars[1] + macChars[0] + " 0x0000" + macChars[5] + macChars[4] + " 0x00000000 0x00000000";
//Output: 0xA8FEE988 0x00002F1F 0x00000000 0x00000000
Update: Based on what you are trying to do, two methods would be better. You could reuse your Mac_Reverso in place of RevertMac below.
//Input 88:E9:FE:A8:1F:2F
//Output 0xA8FEE988 0x00002F1F 0x00000000 0x00000000
public static string ConvertMac(string macAddress)
{
string[] macChars = macAddress.Split(":");
string macRevertido = "0x" + macChars[3] + macChars[2] + macChars[1] + macChars[0] + " 0x0000" + macChars[5] + macChars[4] + " 0x00000000 0x00000000";
return macRevertido;
}
//Input 0xA8FEE988 0x00002F1F 0x00000000 0x00000000
//Output 88:E9:FE:A8:1F:2F
public static string RevertMac(string mc)
{
string revertedMac = "" + mc[8] + mc[9] + ":" + mc[6] + mc[7] + ":" + mc[4] + mc[5] + ":" + mc[2] + mc[3] + ":" + mc[19] + mc[20] + ":" + mc[17] + mc[18];
return revertedMac;
}
This doesn't address the endian issues Neil mentioned. Your question mentions reversing bytes, and your output format implies reversing the order of bytes in the array. Is that your objective?
I need to update the Expiry Date and update the Cardholder Name on an existing card in Realex payments.
The hash value syntax should be in the following format:
Timestamp.merchantID.payerref.ref.expirydate.cardnumber
And here is an example of how it should look
20030516175919.yourmerchantid.mypayer.card01.1015.
When I run the following method I get the error:
"sha1hash incorrect - check your code and the Developers Documentation"
private string ReturnHash(string timeStamp, string merchantId, string payerRef, string reference, string expDate, string cardNum )
{
SHA1 hash = new SHA1Managed();
StringBuilder builder = new StringBuilder();
builder.Append(timeStamp).Append(".");
builder.Append(merchantId).Append(".");
builder.Append(payerRef).Append(".");
builder.Append(reference).Append(".");
builder.Append(expDate).Append(".");
builder.Append(cardNum );
string resultingHash = BitConverter.ToString(hash.ComputeHash(Encoding.UTF8.GetBytes(builder.ToString())));
resultingHash = BitConverter.ToString(hash.ComputeHash(Encoding.UTF8.GetBytes(resultingHash)));
return resultingHash;
}
What am I doing wrong?
Thank you for your message.
Could you try before running this line of code:
string resultingHash = BitConverter.ToString(hash.ComputeHash(Encoding.UTF8.GetBytes(builder.ToString())));
To make "resultingHash" all lowercase?
Also before running:
resultingHash = BitConverter.ToString(hash.ComputeHash(Encoding.UTF8.GetBytes(resultingHash)));
make "resultingHash" to lowercase as well.
Thanks,
Borja
var timeStamp = RealexDateFormatter.DateFormatForRealex();
var orderid = model.ORDER_ID;
var secret = ConfigurationManager.AppSettings["Appsecretkey"];
var merchantId = ConfigurationManager.AppSettings["AppMerchantId"];
var temp1 = FormsAuthentication.HashPasswordForStoringInConfigFile(
timeStamp + "." +
merchantId + "." +
orderid + "." +
model.AMOUNT + "." + "EUR", "sha1");
temp1 = temp1.ToLower();
var temp2 = temp1 + "." + secret;
var sha1hash = FormsAuthentication.HashPasswordForStoringInConfigFile(temp2, "sha1");
sha1hash = sha1hash.ToLower();`enter code here`
var url = "https://hpp.sandbox.realexpayments.com/pay?MERCHANT_ID="
+ ConfigurationManager.AppSettings["AppMerchantId"] +
"&ORDER_ID=" + orderid + "&CURRENCY=EUR" + "&AMOUNT=" + model.AMOUNT + "&TIMESTAMP=" + timeStamp + "&SHA1HASH=" + sha1hash + "&MERCHANT_RESPONSE_URL=http://deposit.projectstatus.in/Payment/Response";
An existing system generated signatures using Bouncy Castle (.NET) and I need to verify these existing signatures using the Microsoft ECDsaCng class.
Consider the following code that attempts to do this:
public static void InterchangeTest()
{
//AsymmetricCipherKeyPair bKeyPair_0 = Crypto.GenerateEcdsaKey();
String sPassPhrase = "bob is your uncle";
byte[] bPassPhrase = new UTF8Encoding(false).GetBytes(sPassPhrase);
int SaltBitSize = 128;
int EcdsaBitLength = 521;
byte[] bSalt = new byte[SaltBitSize / 8];
new SecureRandom().NextBytes(bSalt);
if (EcdsaBitLength != 192 && EcdsaBitLength != 256 && EcdsaBitLength != 521)
{
throw new ArgumentException("Invalid EcdsaBitLength length () " + EcdsaBitLength + " ECDSA supports 192, 256, and 521 bit lengths.");
}
string curveName = "P-" + EcdsaBitLength.ToString();
X9ECParameters ecP = NistNamedCurves.GetByName(curveName);
ECDomainParameters ecSpec = new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECDH");
g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
AsymmetricCipherKeyPair aKeyPair = g.GenerateKeyPair();
ECPrivateKeyParameters mPrivateKey = (ECPrivateKeyParameters)aKeyPair.Private;
ECPublicKeyParameters mPublicKey = (ECPublicKeyParameters)aKeyPair.Public;
byte[] bPrivateKey = ((ECPrivateKeyParameters)aKeyPair.Private).D.ToByteArray();
String SignerName = "SHA-256withECDSA";
ISigner bSigner = SignerUtilities.GetSigner(SignerName);
bSigner.Init(true, aKeyPair.Private);
bSigner.BlockUpdate(bPassPhrase, 0, bPassPhrase.Length);
byte[] bouncySignature = bSigner.GenerateSignature();
ISigner bVerifier = SignerUtilities.GetSigner(SignerName);
bVerifier.Init(false, aKeyPair.Public);
bVerifier.BlockUpdate(bPassPhrase, 0, bPassPhrase.Length);
bool passed = bVerifier.VerifySignature(bouncySignature);
Console.WriteLine("Verified with Bouncy: " + passed);
var xmlImport = "<ECDSAKeyValue xmlns='http://www.w3.org/2001/04/xmldsig-more#'>\n"
+ " <DomainParameters>\n"
+ " <NamedCurve URN='urn:oid:1.3.132.0.35' />\n"
+ " </DomainParameters >\n"
+ " <PublicKey >\n"
+ " <X Value='" + ((ECPublicKeyParameters)aKeyPair.Public).Q.X.ToBigInteger().ToString() + "' xsi:type='PrimeFieldElemType' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' />\n"
+ " <Y Value='" + ((ECPublicKeyParameters)aKeyPair.Public).Q.Y.ToBigInteger().ToString() + "' xsi:type='PrimeFieldElemType' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' />\n"
+ " </PublicKey >\n"
+ " </ECDSAKeyValue>";
//using (StreamWriter outputFile = new StreamWriter(#"C:\Dev\x2.txt"))
//{
// outputFile.WriteLine(xmlImport);
//}
ECDsaCng eccImporter = new ECDsaCng();
eccImporter.FromXmlString(xmlImport, ECKeyXmlFormat.Rfc4050);
Console.WriteLine("hash algorithm = " + eccImporter.HashAlgorithm + " Probably " + CngAlgorithm.Sha256);
Console.WriteLine("Signature algorithm = " + eccImporter.SignatureAlgorithm + " Probably ECDsa");
Console.WriteLine("After import, key size = " + eccImporter.KeySize + " probably 521");
try
{
if (eccImporter.VerifyData(bPassPhrase, bouncySignature))
{
Console.WriteLine("Verified the signature from bouncy castle using .NET");
}
}
catch (CryptographicException e)
{
// "The parameter is incorrect"
Console.WriteLine("Did not verify bouncy signature with .NET because: " + e.Message);
}
CngKey msKey = CngKey.Create(CngAlgorithm.ECDsaP521, null, new CngKeyCreationParameters { ExportPolicy = CngExportPolicies.AllowPlaintextArchiving });
ECDsaCng ms_ecdsaCNG = new ECDsaCng(msKey);
String xmlExport = ms_ecdsaCNG.ToXmlString(ECKeyXmlFormat.Rfc4050);
eccImporter = new ECDsaCng();
eccImporter.FromXmlString(xmlExport, ECKeyXmlFormat.Rfc4050);
byte[] ms_SignedData = ms_ecdsaCNG.SignData(bPassPhrase);
Console.WriteLine("Verify .NET signature with .NET: " + ms_ecdsaCNG.VerifyData(bPassPhrase, ms_SignedData));
Console.WriteLine("Verify .NET signature with imported .NET: " + eccImporter.VerifyData(bPassPhrase, ms_SignedData));
//Console.WriteLine();
//Console.WriteLine(xmlExport);
//Console.WriteLine();
}
Everything works fine until I attempt to verify the signature in with the Microsoft classes, at which point it generates an exception stating that the Parameter is incorrect.
any thoughts?
Maarten Bodewes is correct. My problem is that the signature is encoded using BouncyCastly using ASN.1/DER format. MS uses an smaller format (I think that it is IEEE P-1393). So, I wrote this little routine in C# to transform the signatures.
public static byte[] ConvertDerToP1393(byte[] data)
{
byte[] b = new byte[132];
int totalLength = data[1];
int n = 0;
int offset = 4;
int thisLength = data[offset++];
if (data[offset] == 0) {
// Negative number!
++offset;
--thisLength;
}
for (int i= thisLength; i < 66; ++i) {
b[n++] = 0;
}
if (thisLength > 66) {
System.Console.WriteLine("BAD, first number is too big! " + thisLength);
} else {
for (int i = 0; i < thisLength; ++i) {
b[n++] = data[offset++];
}
}
++offset;
thisLength = data[offset++];
for (int i = thisLength; i < 66; ++i){
b[n++] = 0;
}
if (thisLength > 66) {
System.Console.WriteLine("BAD, second number is too big! " + thisLength);
} else {
for (int i = 0; i < thisLength; ++i) {
b[n++] = data[offset++];
}
}
return b;
}
Although I have done only limited testing, the code has worked with my tests.
I convert private Key to public, with VB:
Dim Point As Org.BouncyCastle.Math.EC.ECPoint = PrivateKey.Parameters.G.Multiply(PrivateKey.D)
Dim ToPublic = New Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters(PrivateKey.AlgorithmName, Point, PrivateKey.PublicKeyParamSet)
dynamic counter = 1;
string FileNameWithoutExtestion = "";
FileNameWithoutExtestion = file.Split('.')[0];
string FileExtestion = file.Split('.')[1];
while (System.IO.File.Exists(Dir + file))
{
if (true)
{
counter = counter + 1;
if (FileNameWithoutExtestion.EndsWith('_'))
{
file = FileNameWithoutExtestion + counter.ToString() + "." + FileExtestion;
}
else
{
file = FileNameWithoutExtestion + "_" + counter.ToString() + "." + FileExtestion;
}
}
}
if (FileNameWithoutExtestion.EndsWith('_')) //the error occurred here
Whats wrong ?
String.EndsWith() only has overloads with string as parameter, you insert a char.
Replace
.EndsWith('_')
with
.EndsWith("_")
and i would use those path-methods to parse filenames and extensions
string FileNameWithoutExtestion = System.IO.Path.GetFileNameWithoutExtension(file);
string FileExtestion = System.IO.Path.GetExtension(file); //.jpg
because FileNameWithoutExtestion = file.Split('.')[0]; will lead to a invalid value in case of a filename like foo.bar.jpg