Im pretty new to programming and I am having a few problems. I am making a windows form program for storing encrypted passwords.
I have created the program in cmd, but I am now converting it to a windows form program. In the cmd version, all the code was in one .cpp file. Now I am trying to use .cpp and .h files to order my code and generally improve it.
I am using crypto++ for encryption. I have got two projects in my solution. One is the cryptlib and the other is my password encryptor project.
Basically, when the main program is loaded, it hides the main form, and opens the login form (Authenticate). This then calls on the login functions to authenticate the login details. Once this is done it closes the login form and shows the main form again.
The problem I am facing is it seems like all the variables being passed to the login functions (the managed code/crypto++) is just being jumbled up. The Password is always blank, and the Username is garbled.
Is there any reason the variable would be destroyed when being passed to my managed code?
(I am using the temp files to debug the username and password)
The AuthenticateLogin funciton:
Code:
bool Password_Encryptor::AuthenticateLogin(string userpass, string Password, string Username){
ofstream out3 ("C:/Users/Default/AppData/Roaming/Pass Holder/temp3.dat");
out3 << "1 " << Username << endl;
out3.close();
ofstream out4 ("C:/Users/Default/AppData/Roaming/Pass Holder/temp4.dat");
out4 << "1 " << Password << endl;
out4.close();
//This function is to make sure the username and password entered by the user is correct
int size;
char *buf;
string hashText;
//Read in the SALT used for the previous userpass
ifstream in1(SALTfile, ios::in | ios::binary | ios::ate);
size = in1.tellg();
buf = new char[size + 1];
buf[size] = 0;
in1.seekg(0, ios::beg);
in1.read(buf, size);
in1.close();
string hexsalt = string(buf);
//Read in the IV used for the previous userpass
ifstream in2(IVfile, ios::in | ios::binary | ios::ate);
size = in2.tellg();
buf = new char[size + 1];
buf[size] = 0;
in2.seekg(0, ios::beg);
in2.read(buf, size);
in2.close();
string hexiv = string(buf);
//Read in the hash used for the previous userpass, this will be compared the to newly entered userpass encrypted with the previous SALT and IV
ifstream in3(UserpassFile, ios::in | ios::binary | ios::ate);
size = in3.tellg();
buf = new char[size + 1];
buf[size] = 0;
in3.seekg(0, ios::beg);
in3.read(buf, size);
in3.close();
string cipherText = string(buf);
//Recover the SALT and IV from the hex values in the file,
PKCS5_PBKDF2_HMAC<SHA256> pbkdf;
SecByteBlock recoveredkey(AES::DEFAULT_KEYLENGTH);
SecByteBlock recoveredsalt(AES::DEFAULT_KEYLENGTH);
StringSource saltDecoder(hexsalt,true,new HexDecoder(new ArraySink(recoveredsalt, recoveredsalt.size() ) ) );
test();
ofstream out1 ("C:/Users/Default/AppData/Roaming/Pass Holder/temp.dat");
out1 << "1 " << Password << endl;
out1 << "1 " << userpass << "\n2 " << Password << endl;
out1 << "1 " << recoveredkey << "\n2 " << recoveredkey.size() << "\n3 " << Password << "\n4 " << Password.size() << "\n5 " <<
recoveredsalt << "\n6 " << recoveredsalt.size() << "\n7 " << iterations ;
out1.close();
pbkdf.DeriveKey(recoveredkey, recoveredkey.size(), 0x00, (byte *) Password.data(), Password.size(), recoveredsalt, recoveredsalt.size(), iterations);
test();
SecByteBlock recoverediv(AES::BLOCKSIZE);
StringSource ivDecoder(hexiv,true,new HexDecoder(new ArraySink(recoverediv, recoverediv.size() ) ) );
//Encrypt the userpass that has been entered, using the SALT and IV stored in the file
SecByteBlock derivedkey(AES::DEFAULT_KEYLENGTH);
//Buffer that holds the derived key, purpose byte (unused), password bytes, salt bytes, iteration count (large as you can tolerate)
pbkdf.DeriveKey(derivedkey, derivedkey.size(), 0x00, (byte *) Password.data(), Password.size(), recoveredsalt, recoveredsalt.size(), iterations);
//Encrypt the userpass using key derived above, storing the hex encoded result into hashtext
CBC_Mode<AES>::Encryption aesencryption(derivedkey,derivedkey.size(),recoverediv);
StringSource encryptor(userpass, true, new StreamTransformationFilter(aesencryption, new HexEncoder( new StringSink(hashText))) );
//Return whether the comparison between the newly created hash, and the old hash is correct
return (hashText == cipherText);
}
Code:
The function that calls it (Auth):
Code:
void Authenticate::Auth() {
if (chances == 0) {
MessageBox::Show("You have failed 3 times, the application will now close", "Bad Login");
Close();
}
String ^UsernameTemp = Authenticate::TbUsername->Text;
String ^PasswordTemp = Authenticate::TbPassword->Text;
string Username, Password;
int Ulen, Plen;
char *Uch, *Pch;
bool Uresult, Presult;
pin_ptr<const wchar_t> Uwch = PtrToStringChars( UsernameTemp );
Ulen = (( UsernameTemp->Length+1) * 2);
Uch = new char[ Ulen ];
Uresult = wcstombs( Uch, Uwch, Ulen ) != -1;
Username = Uch;
delete Uch;
pin_ptr<const wchar_t> Pwch = PtrToStringChars( PasswordTemp );
Plen = (( PasswordTemp->Length+1) * 2);
Pch = new char[ Plen ];
Presult = wcstombs( Pch, Pwch, Plen ) != -1;
Password = Pch;
delete Pch;
string userpass = Username + Password;
//If there was no username + pasword file (found earlier), then create one with the newly entered info
if (!filexists){
EncryptUserpass(userpass, Password);
}
ofstream out1 ("C:/Users/Default/AppData/Roaming/Pass Holder/temp1.dat");
out1 << "1 " << Username << endl;
out1.close();
ofstream out2 ("C:/Users/Default/AppData/Roaming/Pass Holder/temp2.dat");
out2 << "1 " << Password << endl;
out2.close();
//Authenticate the login details
login = AuthenticateLogin(userpass, Password, Username);
if ( login == true ) {
MessageBox::Show("Login Successful", "Authentication", MessageBoxButtons::OK);
Authenticate::Close();
} else {
MessageBox::Show("Login Failed /n/n You have " + chances + " chance(s) remaining!", "Authentication", MessageBoxButtons::OK);
chances --;
this->TbUsername->Text = "";
this->TbPassword->Text = "";
}
};
Basically the line 'login = AuthenticateLogin(userpass, Password, Username);' is running, but when the variable are passed, they are garbled and meaningless. I have checked the variable before they are passed, and they are as they should be. Only when passed to the managed code are they destroyed.
Is there any concrete demand to use Crypto++ at all? If not, it may be by far simpler to instead use the .NET Cryptographic Services as discussed in http://www.codeguru.com/forum/showthread.php?t=506715. Comibing both native and managed code in a single C++/CLI project is possible (and in fact this is considered the primary strength of C++/CLI), but it should only be done when really, really needed, since it tends to big-time complicate things, in particular for beginners.
If, as I understand you, you've already got a working command line version of your program, it may even be simpler to just write a GUI wrapper for that as discussed in http://www.codeguru.com/forum/showthread.php?t=519546.
BTW, to me it looks like this excerpt from your second code snippet:
Code:
//Authenticate the login details
login = AuthenticateLogin(userpass, Password, Username);
can't even call the function of that name from the first snippet at all, at least not directly: The functions from the two snippets seem to be members of different classes (Password_Encryptor and Authenticate), one of which is native and one managed. OTOH, the unqualified call to AuthenticateLogin() quoted above would either call a member function of its own class (i.e. Authenticate), of one of its base classes or a free function. However, AFAIK managed and native functions can't be mixid within the same class, nor can a managed class be derived from a native one or vice versa (which would essentially lead to the same result).
Last edited by Eri523; March 15th, 2012 at 03:29 PM.
I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.
This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.
Well I would prefer to use Crypto++ if possible, just because I know how it works now I did originally use CAPICOM, but then started using crypto++ as CAPICOM was older and not being updated anymore
That call to 'AuthenticateLogin' does work in sorts, as it runs the function (I know this because the temp files are written to at the beginning of the function), I just don't think it likes it!
Is there any way I can stay with crypto++, and call that function without any problems occurring?
Ok, this demanded some research (in particular because I have never used Crypto++ myself, neither in managed nor in native code) and testing. I couldn't find a managed wrapper for Crypto++ (as alredy mentioned but not cleared in the earlier crypto thread I linked to), at least none that more or less exposes the Crypto++ functionality 1-to-1. However, perhaps you find one yourself, maybe starting from http://www.cryptopp.com/wiki/Related_Links. If there actually isn't such a wrapper somewhere and you could come up with one you've writen yourself, the community would likely appreciate it, given how comprehensive and popular that library seems to be. OTOH, especially its comprehensiveness will probably make that a lot of work...
Finding a native wrapper for Crypto++ probably would be the easiest way to handle things, however, in the meantime we can try to tackle your actual concrete problem, and that seems to boil down to passing strings from managed to native code. Crypto++ itself probably isn't even involved at all. So I tried to build a simpler model of what is or is not going on:
Code:
// Test2.cpp: Hauptprojektdatei.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vcclr.h>
#pragma managed(push, off)
void native_function(std::string strNative1, std::string strNative2)
{
std::cout << strNative1 << std::endl;
std::cout << strNative2 << std::endl;
}
#pragma managed(pop)
using namespace System;
// Conversion function written according to http://msdn.microsoft.com/en-us/libr...v=vs.100).aspx
// Already used almost the same code in http://www.codeguru.com/forum/showthread.php?p=2012459
std::string ToNativeString(String ^strManaged)
{
pin_ptr<const wchar_t> wch = PtrToStringChars(strManaged);
size_t origsize = wcslen(wch) + 1;
size_t nConvertedChars = 0;
char *pConvertedChars = new char[origsize];
wcstombs_s(&nConvertedChars, pConvertedChars, origsize, wch, _TRUNCATE);
std::string strNativeStringToReturn(pConvertedChars);
delete [] pConvertedChars;
return strNativeStringToReturn;
}
int main(array<System::String ^> ^args)
{
String ^strManaged1 = "Username";
String ^strManaged2 = "Password";
native_function(ToNativeString(strManaged1), ToNativeString(strManaged2));
Console::WriteLine("Hit <Enter> to continue...");
Console::ReadLine();
return 0;
}
The code I use here to convert managed strings into native ones is quite similar to yours; we seem to both have based our code on the same or related sources. The main difference, however, is that mine works.
After having written the sample code above (and if I had seen that before I may not have written in at all), comparing it to your code again I found out that you're using delete the wrong way: You're calling delete to deallocate your chararrays, when you should have used delete [] instead. That's generally a no-no, but when initially finding that, I thought that it may cause heap corruption but not garbled strings to be passed to the function you call. Butstd::string of course stores its string data on the heap so the faulty delete could very well be the culprit.
So I suggest you first fix the two faulty deletes and see whether that fixes the problem. If it doesn't, I suggest you try to modify my sample code above so that it reproduces your failure. That may give us a much simpler model to work with, which is generally helpful, but particularly in forum discussions.
BTW, every once a while the discussion comes up whether using the wrong form of delete on arrays of PODs like char actually would even matter at all (though, of course, it definitely is against the standard which says it provokes undefined behavior). If the wrong delete actually is the culprit here, this would be one of the rare (in fact, I can't remember having ever seen one myself at all) proofs of the fact that it very well does matter for POD arrays.
I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.
This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.
After about 2 hours of changing stuff, moving around functions and adding and removing lines. Finally I have solved the problem by including the two lines:
#pragma managed(push, off) &
#pragma managed(pop)
The first just above all the crypto++ functions and the second just above the conversion functions.
Thank you so much! After a week of fighting hard with this program to make it work, it now does
The first just above all the crypto++ functions and the second just above the conversion functions.
So you mean you've written your own application code into the Crypto++ library source files? No good idea I'd say. If you actually even do need some of the library source files as part of your project, better leave them unmodified and turn off CLR support for these specific files in their project properties. Better yet, compile the library as a separate unmanaged project, as a static library or a DLL (I think I've seen on the Crypto++ pages that there's a DLL setup available).
I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.
This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.
Bookmarks