System.Security.Cryptography.CryptographicException: Object already exists - c#

It's weird. I had this method to encrypt a string:
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Assert, Unrestricted = true)]
public static string Encrypt(this string stringToEncrypt, string key) {
var cspp = new CspParameters {
KeyContainerName = key,
Flags = CspProviderFlags.UseMachineKeyStore
};
var rsa = new RSACryptoServiceProvider(cspp) {
PersistKeyInCsp = true
};
var bytes = rsa.Encrypt(System.Text.Encoding.UTF8.GetBytes(stringToEncrypt), true);
return BitConverter.ToString(bytes);
}
And this was my client:
private const string EncryptionKey = "pezhman";
static Random random = new Random();
public static int CreateSalt() {
return random.Next(1000, 9999);
}
public void EncryptSomething() {
var salt = CreateSalt();
var plainText = salt + "," + DateTime.Now;
var encryptionSaltKey = EncryptionKey + DateTime.Now.Date;
// here im calling encryptor:
var encryptedValue = plainText.Encrypt(encryptionSaltKey);
}
I was using this in an ASP.NET MVC 4 application. It was working perfectly; but suddenly it stopped working. Actually, in local, I have no problem and it works. But, when I publish my code to the server, I get this error:
System.Security.Cryptography.CryptographicException: Object already
exists.
Do you have any idea what's happening here? I know I can grant access to the key to everyone. What I'm asking is, what just happened at the server? What is changed? What kind of changes can cause the problem?

What I'm asking is, what just happened at the server? What is changed? What kind of changes can cause the problem?
One possibility is the recently released Windows secuirty update MS14-059, although I can't explain the error message you are getting.
Basically, that update completely uninstalls MVC 4.0.0.0 and replaces it with 4.0.0.1 on your server, and it has caused grief for many people with broken builds. Since cryptography might depend on something very specific to the version number of the DLL, you might want to start there. You can prove or disprove this theory by testing your application on a machine without the above security patch installed to see if it starts working again.

Related

LookupAccountSid() throws System.AccessViolationException on Server 2016

I use pinvoke implementations of LookupAccountSid in managed C# code for several years.
On a German Windows Server 2016 it starts throwing an System.AccessViolationException when resolving S-1-5-11 (Authenticated users) where the German name is: "NT-Authorität\Authentifizierte Benutzer".
I tested 3 different impementations to rule out an pinvoke error. They all throw at the same call.
From the github vanara project and my discussion with the author
First SO implementation
Second SO implementation where I can't find the source at the moment.
They all throw the same exception so it may be a general problem in the api. Probably because of the umlaut Ä in the name?
Similar question at SO
This question sounds similar but this is not the problem I face.
My expirience in earlier projects
I used the implementation from (2.) years ago in a Windodws 7 / Server 2008 environment without any problems, but unfortunatelly I currently have no such systems to verify my recent code.
Similar reported issue
I found this thread regarding a similar behaviour on a french system
My current workaround is
ntAccountName = realSid.Translate(typeof(NTAccount)).ToString();
AdvApi32.LookupAccountName(systemName, ntAccountName, out foundSid, out domainName, out sidNameUse)
But sid.Translate(..) throws when passing a foreign principal an I don't know how reliable it is in other cases.
Questions
Is there any known issue with this api and how to solve it?
Is there any other workaround? (The LsaLookupSids can't be uses because the do not return the SID_NAME_USE flags)
I wrote the following, using the Vanara libraries and #RbMm's comments, to mimic the LookupAccountSid functionality using LsaLookupSids.
private static NTStatus LookupAccountSid2([Optional] string lpSystemName, PSID lpSid, out string lpName,
out string lpReferencedDomainName, out SID_NAME_USE peUse)
{
lpName = lpReferencedDomainName = null;
peUse = default;
using var pol = LsaOpenPolicy(LsaPolicyRights.POLICY_LOOKUP_NAMES, lpSystemName);
var ret = LsaLookupSids2(pol, LsaLookupSidsFlags.LSA_LOOKUP_RETURN_LOCAL_NAMES, 1, new[] { lpSid }, out var refDom, out var names);
if (ret.Failed) return ret;
using (refDom)
using (names)
{
lpReferencedDomainName = refDom.ToStructure<LSA_REFERENCED_DOMAIN_LIST>().DomainList.First().Name;
var name = names.ToArray<LSA_TRANSLATED_NAME>(1)[0];
lpName = name.Name;
peUse = name.Use;
}
return ret;
}
For those who are not familiar with the vanara library and how to convert a SecurityIdentifier to a PSID pointer here is a wrapper for the accepted answer. To use the library just get the nuget package Vanara.AdvApi32
using Vanara.PInvoke;
public static bool LookupAccountSid2(string lpSystemName, SecurityIdentifier sid, out string samAccountName,
out string domainName, out AdvApi32.SID_NAME_USE useFlags)
{
using (AdvApi32.SafePSID safePSID = new AdvApi32.SafePSID(sid))
{
PSID lpSid = new PSID(safePSID);
/// call the actual implementation from: https://stackoverflow.com/a/65202841/1574221
return LookupAccountSid2(lpSystemName, lpSid, out samAccountName, out domainName, out useFlags);
}
}

Caching PIN in multiple CMS Signatures

Well, most of the questions/answers I've found here are regarding not caching a Smartcard PIN which is the opposite case of what I'm looking for.
We have a console application that signs multiple hashes. For this we use Pkcs.CmsSigner because we need to validate the signed hashes server-side.
Normally a Smartcard's PIN should be cached automatically in the CSP per process and it does in Windows 7, but if we run our code in W10 it does not. Also we support both CNG and non-CNG certificates.
The method we use to sign is the following:
public string SignX509(string data, bool chkSignature, string timestampServer, X509Certificate2 selectedCertificate)
{
CmsSigner oSigner = null;
SignedCms oSignedData = null;
string hashText = String.Empty;
try
{
if (chkSignature)
{
oSigner = new CmsSigner();
oSigner.Certificate = selectedCertificate;
byte[] arrDataHashed = HashSHA1(data);
// hash the text to sign
ContentInfo info = new ContentInfo(arrDataHashed);
// put the hashed data into the signedData object
oSignedData = new SignedCms(info);
if (string.IsNullOrEmpty(timestampServer)) {
oSigner.SignedAttributes.Add(new Pkcs9SigningTime(DateTime.Now));
}
else {
TimeStampToken tsToken = GetTSAToken(arrDataHashed, timestampServer);
AsnEncodedData timeData = new Pkcs9AttributeObject(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.IdAASigningCertificate.Id, tsToken.GetEncoded());
oSigner.UnsignedAttributes.Add(timeData);
oSigner.SignedAttributes.Add(new Pkcs9SigningTime(tsToken.TimeStampInfo.GenTime.ToLocalTime()));
}
// sign the data
oSignedData.ComputeSignature(oSigner, false);
hashText = Convert.ToBase64String(oSignedData.Encode());
}
else
{
// just clean the hidden hash text
hashText = String.Empty;
}
}
catch (Exception ex)
{
Console.WriteLine("ERRNO [" + ex.Message + " ]");
return null;
}
return hashText;
}
What we've tried so far:
Using RSACryptoServiceProvider to explicitly persist the key in the CSP
RSACryptoServiceProvider key = (RSACryptoServiceProvider)cmsSigner.Certificate.PrivateKey;
key.PersistKeyInCsp = true;
This works if we use the SignHash method but as I've said before, we need to verify the signed data server-side and we do not have access to the certificate, therefore we need a PKCS envelope. If I set this bool and sign using the CMS code the behaviour is the same.
Setting the PIN programmatically
Another try was setting the PIN programmatically via CryptoContext, based on this answer:
private void SetPinForPrivateKey(X509Certificate2 certificate, string pin) {
if (certificate == null) throw new ArgumentNullException("certificate");
var key = (RSACryptoServiceProvider)certificate.PrivateKey;
var providerHandle = IntPtr.Zero;
var pinBuffer = System.Text.Encoding.ASCII.GetBytes(pin);
// provider handle is implicitly released when the certificate handle is released.
SafeNativeMethods.Execute(() => SafeNativeMethods.CryptAcquireContext(ref providerHandle,
key.CspKeyContainerInfo.KeyContainerName,
key.CspKeyContainerInfo.ProviderName,
key.CspKeyContainerInfo.ProviderType,
SafeNativeMethods.CryptContextFlags.Silent));
SafeNativeMethods.Execute(() => SafeNativeMethods.CryptSetProvParam(providerHandle,
SafeNativeMethods.CryptParameter.KeyExchangePin,
pinBuffer, 0));
SafeNativeMethods.Execute(() => SafeNativeMethods.CertSetCertificateContextProperty(
certificate.Handle,
SafeNativeMethods.CertificateProperty.CryptoProviderHandle,
0, providerHandle));
}
With this approach I am able to disable the PIN prompt by setting the PIN programmatically. The problem here is that I have to read the PIN the first time so I can set it in the subsequent signatures.
I've tried to read the PIN from the prompt using CryptoGetProvParam with the dwParam PP_ADMIN_PIN and PP_KEYEXCHANGE_PIN but without luck. My two guesses here are:
I'm not reading in the right time or way
CMS uses a different handler internally
Question 1:
Is there any way to read the PIN set in the Windows prompt?
Question 2:
If reading the PIN is not possible, is there any other way to force PIN caching?
Only now realized this question is still without an answer although we managed to bypass the whole 'read the PIN from Windows prompt' question.
This method does not answer my first question but I'll be answering the second question.
There was a bug in the smartcard CSP provider that disabled the PIN cache for all requests to SignHash even though they were made in the same process.
The smartcard provider has a SDK that exposes some smartcard operations, being one of those an operation to validate the smartcard PIN.
What we ended up doing was to create a simple WPF window that requests the user's PIN and uses the SDK to validate the PIN. If it is correct we use the method that I posted in the original question to force the PIN cache:
Another try was setting the PIN programmatically via CryptoContext, based on this answer:
private void SetPinForPrivateKey(X509Certificate2 certificate, string pin) {
if (certificate == null) throw new ArgumentNullException("certificate");
var key = (RSACryptoServiceProvider)certificate.PrivateKey;
var providerHandle = IntPtr.Zero;
var pinBuffer = System.Text.Encoding.ASCII.GetBytes(pin);
// provider handle is implicitly released when the certificate handle is released.
SafeNativeMethods.Execute(() => SafeNativeMethods.CryptAcquireContext(ref providerHandle,
key.CspKeyContainerInfo.KeyContainerName,
key.CspKeyContainerInfo.ProviderName,
key.CspKeyContainerInfo.ProviderType,
SafeNativeMethods.CryptContextFlags.Silent));
SafeNativeMethods.Execute(() => SafeNativeMethods.CryptSetProvParam(providerHandle,
SafeNativeMethods.CryptParameter.KeyExchangePin,
pinBuffer, 0));
SafeNativeMethods.Execute(() => SafeNativeMethods.CertSetCertificateContextProperty(
certificate.Handle,
SafeNativeMethods.CertificateProperty.CryptoProviderHandle,
0, providerHandle));
}
With this we are able to request the PIN only one time when signing multiple hashes until the smartcard provider fixes the bug on their side.

Getting exception on server when using RSA via CSharp-easy-RSA-PEM

I have used https://github.com/jrnker/CSharp-easy-RSA-PEM for RSA implementation in my mvc project.
It's working fine in my local machine in IIS & also via visual studio but when I deploy my application on server, it gives me below exception.
"System.NullReferenceException: Object reference not set to an instance of an object.\r\n at CoreEntities.Classes.Utility.RSADecrypt(String input)\r\n at WebAPI.Attributes.ApiAuthorizeAttribute.Authorize(HttpActionContext actionContext)"
My code is :
public static string RSADecrypt(string input)
{
try
{
string priv = File.ReadAllText(HostingEnvironment.MapPath("~/Certificates/consumer.pem"));
RSACryptoServiceProvider privc = Crypto.DecodeRsaPrivateKey(priv);
return Crypto.DecryptString(input, privc);
}
catch (Exception ex)
{
throw ex;
}
}
I posted my issue on github also # https://github.com/jrnker/CSharp-easy-RSA-PEM/issues/8
After debugging a lot, I figured out that system is not creating an object of RSACryptoServiceProvider
CspParameters parms = new CspParameters();
parms.Flags = CspProviderFlags.NoFlags;
parms.KeyContainerName = Guid.NewGuid().ToString().ToUpperInvariant();
parms.ProviderType = ((Environment.OSVersion.Version.Major > 5) || ((Environment.OSVersion.Version.Major == 5) && (Environment.OSVersion.Version.Minor >= 1))) ? 0x18 : 1;
// Exception is comping in below line.
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(parms);
RSAParameters rsAparams = new RSAParameters();
Exception:- System.Security.Cryptography.CryptographicException: The system cannot find the file specified.\r\n\r\n at CoreEntities.Classes.Utility.RSADecrypt(String input)\r\n at WebAPI.Attributes.ApiAuthorizeAttribute.Authorize(HttpActionContext actionContext)
Can anyone please help...
#Downvoters, Kindly pay attention.
I found solution to this problem.
This problem is mainly due to the new security constraints that were included into windows server 2008 onwards.
In windows server 2008 a new user with name CryptoGraphic Operator will be created by default.
If your application is using RSACryptoServiceProvider and when you decide to host your application on windows server 2008 IIS7 follow below steps
the account under which the respective application pool of the virtual directory that you create is running should be added in to CryptoGraphic Operator user.
Open IIS7 --> ApplicationPools --> YourAppPool -->RighClikck --> Advanced Settings ---> Load User Profile set this value to true.
This solved my problem.
Ref:- https://social.msdn.microsoft.com/Forums/vstudio/en-US/ec93922a-fd1e-4225-b5cf-1472ebb3acd1/systemsecuritycryptographycryptographicexception-the-system-cannot-find-the-file-specified?forum=netfxbcl
I solved the problem by changing the process Like below and no need to maniupulate the web server (IIS, NGINX or any other). I also tested that on linux, works fine.
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xmlPrivateKey);
string toBeSigned= "string";
byte[] signMain = rsa.SignData(Encoding.UTF8.GetBytes(toBeSigned), new SHA1CryptoServiceProvider());
string signature = Convert.ToBase64String(signMain);

Drag/drop from outlook to internet explorer via BHO doesn't work on x32/86 machines

I'm currently implementing a browser helper object which would allow dragging emails from the outlook to the internet explorer's page.
I'm following the approach described in the following post: Implementing a Drag-and-Drop function from MS Outlook into our web application. I've got it working but only on x64 machines. On the x32/86 machines i'm getting the exception in the following piece of code (obviously i've replaced real filename inserting with fake one for simplicity):
DropFiles df = new DropFiles();
string filename = #"D:\projects\hello.txt";
byte[] binaryData = Encoding.Unicode.GetBytes(filename);
binaryData = binaryData.Concat(new byte[] { 0, 0 }).ToArray();
IntPtr pointerToGlobalMemory = Marshal.AllocHGlobal(Marshal.SizeOf(df) + binaryData.Length);
df.Files = Marshal.SizeOf(df);
df.Wide = true;
Marshal.StructureToPtr(df, pointerToGlobalMemory, true);
IntPtr newPointer = new IntPtr(pointerToGlobalMemory.ToInt32() + Marshal.SizeOf(df));
Marshal.Copy(binaryData, 0, newPointer, binaryData.Length);
var descriptorFormat = new COMInterop.FORMATETC();
descriptorFormat.cfFormat = HdropDescriptorId; // 15
descriptorFormat.ptd = IntPtr.Zero;
descriptorFormat.dwAspect = COMInterop.DVASPECT.DVASPECT_CONTENT;
descriptorFormat.lindex = -1;
descriptorFormat.tymed = COMInterop.TYMED.TYMED_HGLOBAL;
var td = new COMInterop.STGMEDIUM();
td.unionmember = pointerToGlobalMemory;
td.tymed = COMInterop.TYMED.TYMED_HGLOBAL;
dataObject.SetData(ref descriptorFormat, ref td, true);
On the executing the last ling of this code (actually setting the fake HDROP descriptor) i'm getting the following exception:
"Invalid FORMATETC structure (Exception from HRESULT: 0x80040064 (DV_E_FORMATETC))".
Did someone experienced described problem or have an idea what can be the reason of this issue?
To be more specific about environment - i'm having this trouble on win7 32 bit with IE 10 but i'm pretty sure that the reason especially in that machine is 32 bit.
You need to implement your own IDataObject and pass it to the original IDropTarget.Drop instead of hijacking an existing IDataObject coming from Outlook.

Modify Emdeded String in C# compiled exe

I have an issue where I need to be able to have a compiled exe ( .net 3.5 c# ) that I will make copies of to distribute that will need to change a key for example before the exe is sent out.
I cannot compile each time a new exe is needed. This is a thin client that will be used as part of a registration process.
Is it possible to add a entry to a resource file with a blank value then when a request comes in have another application grab the blank default thin client, copy it, populate the blank value with the data needed.
If yes how? If no do you have any ideas? I have been scratching my head for a few days now and the limitation as due to the boundaries I am required to work in.
The other idea I has was to inject the value into a method, which I have no idea how I would even attempt that.
Thanks.
Convert the assembly to IL, do a textual search and replace, recompile the IL to an assembly again. Use the standard tools from the .NET SDK.
Instead of embedding the key in the assembly, put it in the app.config file (or another file delivered with the application) and prevent your application from running if the key is not present and valid. To protect it against modification by users, also add an RSA signature the config file.
This code could be used to generate XML containing your key.
public static void Main()
{
Console.WriteLine(GenerateKey());
}
public static Byte[] Transform(Byte[] bytes, ICryptoTransform xform)
{
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{
using (CryptoStream cstream = new CryptoStream(stream, xform, CryptoStreamMode.Write))
{
cstream.Write(bytes, 0, bytes.Length);
cstream.Close();
stream.Close();
return stream.ToArray();
}
}
}
public static string GenerateKey()
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
// This is the private key and should never be shared.
// Generate your own with RSA.Create().ToXmlString(true).
String rsaPrivateKey = "<RSAKeyValue><Modulus>uPCow37yEzlKQXgbqO9E3enSOXY1MCQB4TMbOZyk9eXmc7kuiCMhJRbrwild0LGO8KE3zci9ETBWVVSJEqUqwtZyfUjvWOLHrf5EmzribtSU2e2hlsNoB2Mu11M0SaGd3qZfYcs2gnEnljfvkDAbCyJhUlxmHeI+35w/nqSCjCk=</Modulus><Exponent>AQAB</Exponent><P>4SMSdNcOP0qAIoT2qzODgyl5yu9RubpIU3sSqky+85ZqJHXLUDjlgqAZvT71ROexJ4tMfMOgSWezHQwKWpz3sw==</P><Q>0krr7cmorhWgwCDG8jmzLMo2jafAy6tQout+1hU0bBKAQaPTGGogPB3hTnFIr84kHcRalCksI6jk4Xx/hiw+sw==</Q><DP>DtR9mb60zIx+xkdV7E8XYaNwx2JeUsqniwA3aYpmpasJ0N8FhoJI9ALRzzp/c4uDiuRNJIbKXyt6i/ZIFFH0qw==</DP><DQ>mGCxlBwLnhkN4ind/qbQriPYY8yqZuo8A9Ggln/G/IhrZyTOUWKU+Pqtx6lOghVdFjSxbapn0W8QalNMFGz7AQ==</DQ><InverseQ>WDYfqefukDvMhPHqS8EBFJFpls/pB1gKsEmTwbJu9fBxN4fZfUFPuTnCIJsrEsnyRfeNTAUFYl3hhlRYZo5GiQ==</InverseQ><D>qB8WvAmWFMW67EM8mdlReI7L7jK4bVf+YXOtJzVwfJ2PXtoUI+wTgH0Su0IRp9sR/0v/x9HZlluj0BR2O33snQCxYI8LIo5NoWhfhkVSv0QFQiDcG5Wnbizz7w2U6pcxEC2xfcoKG4yxFkAmHCIkgs/B9T86PUPSW4ZTXcwDmqU=</D></RSAKeyValue>";
rsa.FromXmlString(rsaPrivateKey);
String signedData = "<SignedData><Key>Insert your key here</Key></SignedData>";
Byte[] licenseData = System.Text.Encoding.UTF8.GetBytes(signedData);
Byte[] sigBytes = rsa.SignData(licenseData, new SHA1CryptoServiceProvider());
String sigText = System.Text.Encoding.UTF8.GetString(Transform(sigBytes, new ToBase64Transform()));
System.Text.StringBuilder sb = new StringBuilder();
using (System.Xml.XmlWriter xw = System.Xml.XmlTextWriter.Create(sb))
{
xw.WriteStartElement("License");
xw.WriteRaw(signedData);
xw.WriteElementString("Signature", sigText);
xw.WriteEndElement();
}
return sb.ToString();
}
Example output from this code:
<?xml version="1.0" encoding="utf-16"?>
<License>
<SignedData>
<Key>Insert your key here</Key>
</SignedData>
<Signature>cgpmyqaDlHFetCZbm/zo14NEcBFZWaQpyHXViuDa3d99AQ5Dw5Ya8C9WCHbTiGfRvaP4nVGyI+ezAAKj287dhHi7l5fQAggUmh9xTfDZ0slRtvYD/wISCcHfYkEhofXUFQKFNItkM9PnOTExZvo75pYPORkvKBF2UpOIIFvEIU=</Signature>
</License>
Then you can use code like this to verify it. You never have to distribute the private key:
public static Boolean CheckLicenseSignature(String licXml)
{
try
{
System.Xml.XmlDocument xd = new System.Xml.XmlDocument();
xd.LoadXml(licXml);
String licSig = xd.SelectSingleNode("/License/Signature").InnerText;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
String rsaPublicKey = "<RSAKeyValue><Modulus>uPCow37yEzlKQXgbqO9E3enSOXY1MCQB4TMbOZyk9eXmc7kuiCMhJRbrwild0LGO8KE3zci9ETBWVVSJEqUqwtZyfUjvWOLHrf5EmzribtSU2e2hlsNoB2Mu11M0SaGd3qZfYcs2gnEnljfvkDAbCyJhUlxmHeI+35w/nqSCjCk=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
rsa.FromXmlString(rsaPublicKey);
Byte[] licenseData = System.Text.Encoding.UTF8.GetBytes(xd.SelectSingleNode("/License/SignedData").OuterXml);
return rsa.VerifyData(licenseData, new SHA1CryptoServiceProvider(), Transform(System.Text.Encoding.UTF8.GetBytes(licSig), new FromBase64Transform()));
}
catch (System.Xml.XmlException ex)
{
return false;
}
catch (InvalidOperationException ex)
{
return false;
}
}
From within the capability of the .NET code itself, I'm not sure if this is doable. But it is possible to dynamically generate a .NET DLL which contains some key that can be referred from the main application. That is, if you wouldn't mind a second file in the distribution.
Or if you don't mind to use Ildasm to disassemble the .exe, change the key, then use Ilasm to reassemble, then you can do something to automate that.
The accepted answer is GARBAGE!
I HAVE DONE THIS SUCCESSFULLY. MUCH EASIER
Just put your base application (.net) that needs the key somewhere with a string resource FILLED WITH "XXXXXXXXXXXXXXX" (more than you'll need)
.Net resources are usually kept at the top of the code so you will find them fast skipping the first 100,000 bytes in my case.
Then you just read it in and look for those XXXXXX's. When you find them you replace them with the real API key and replace the rest of the X's with spaces you just trim off in code. This is the answer. It works and it works well.
ApiToken at = new ApiToken(UserId, SelectedCID);
at.MakeToken();
byte[] app = System.IO.File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.GetData("DataDirectory").ToString(), "notkeyedapp.exe"));
for (int i = 100000; i < app.Length; i++)
{
if (app[i] == 0x58 && app[i + 1] == 0x58 && app[i + 2] == 0x58)
{
for (int j = 0; j < 128; j++)
{
if (at.Token.Length >= j + 1)
app[i + j] = System.Text.Encoding.ASCII.GetBytes(at.Token[j].ToString())[0];
else
app[i + j] = 0x20;
}
break;
}
}
string filename = "SoftwareProduct for - " + BaseModel.CompanyName.Replace(".", "") + ".exe";
return File(app, System.Net.Mime.MediaTypeNames.Application.Octet, filename);
I don't think You can get away without recompiling Your .exe and having key embedded into said .exe. The compilation process can be automated though via use of ildasm.exe and ilasm.exe as Daniel Earwicker suggested in his response https://stackoverflow.com/a/2742902/2358659
I'd like to expand on that if anyone else stumbles across this topic in the future.
I recently was facing similar problem due to my poor source code version control habits. In a nutshell I had an executable that was supposed to write some data to a Google Spreadsheet by referencing it's ID. Long after executable was released came another request from a different team to use the tool, but it had to write same information into a different spreadsheet in order to keep data separate for two teams. At the time I did not have the original source code, hence I was not able to change the static variable holding the original spreadsheet ID. What I did was as follows:
Using CMD.exe → call "C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\ildasm.exe" "myApplication.exe" /out="myApplication.il"
Using Notepad++ → Find and replace original ID to new ID inside myApplication.il file. This action can also be automated by writing own C# application to do this, or using PowerShell, or using vb/j-script or using some other find and replace tool available off-the-shelf, like FART (using CMD.exe → call fart.exe myApplication.il "OldKey" "NewKey")
Using CMD.exe → call "C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe" "myApplication.il" /res="myApplication.res" /key="myApplicationKeyFile.snk"
As You see, all of these steps can be put into one .bat file that takes "NewKey" as an input and produces new .exe with NewKey embedded.
I hope that helps.
What comes to my mind, but not tried yet: Create a default String in your program, for example as
static public string regGuid = "yourguidhere";
Then, search the compiled EXE with any decent hex editor. If you find the string, replace it with another test. If you still can execute the program, you could try to automate this process and voila! Here you are.

Categories

Resources