Page 1 of 1
Encyrpting data (like a password)
Posted: Thu Jun 30, 2011 6:46 pm
by purebuilt
Hello all,
I am storing passwords in a database and I would like to encrypt them with just a key of some kind. I have been through the methods and I don't really get them. I need ascii output. I need to be able to encyrpt the password then decypt it later. Both functions.
The passwords are sometimes longer than 8 characters too. Any suggestions? I am looking for the simplest solution. I just need something basic to obsure them in case the database winds up in the wrong hands.
Thanks.
DB
Re: Encyrpting data (like a password)
Posted: Thu Jun 30, 2011 8:11 pm
by Foz
The correct way of doing it is to generate a hash code (i.e. SHA1Fingerprint()) from the password + "salt" (salt being your own random set of characters), and then store that. This way, there is no chance of decrypting the password - the hash is irreversable.
Then on the client you take the password, generate the hash + "salt" and pass that up to the server to compare with what is on the database!
If you require ascii transmission, then also use the Base64 functions to do just that.
Note that you will never be able to recover a password, only replace it with a new one.
Re: Encyrpting data (like a password)
Posted: Thu Jun 30, 2011 8:16 pm
by purebuilt
Actually I am storing the passwords so that the system logs you on and this is not comparing two hashes. I need to be able to reverse the hash so that the system can send the password to the system it is calling. In other words, I have a tool that allows you to pick a system and it logs you one providing user name and password. So the passwords in the database need to be encrypted and then decrypted for use.
Is there an easy way to do that?
Thanks.
DB
Re: Encyrpting data (like a password)
Posted: Thu Jun 30, 2011 8:24 pm
by Foz
Sure, it'll never be completely safe though.
The simplest method is to XOR the string with a key. See this tip here:
http://www.purebasic.fr/english/viewtop ... 12&t=46613
A more secure, though more complex encryption is blowfish:
http://www.purebasic.fr/english/viewtop ... 03#p346403
Re: Encyrpting data (like a password)
Posted: Thu Jun 30, 2011 11:24 pm
by ultralazor
keygen off typed pass for some block cipher like aes or twofish, if result equals typed then it's correct..public key connection to prevent MITM via self-signed ssl or cgi rsa..
RSA has export laws though even though most governments have the computing power to brute it in days..
keygen off typed pass is 'proper' though
Re: Encyrpting data (like a password)
Posted: Thu Jun 30, 2011 11:33 pm
by kenmo
PB has AES functions built in... these should be fine for this. The only catch is their output (and decryption input) is binary data in memory buffers, not normal strings. But like Foz said, you can use the Base64 functions also built in, to convert between binary buffers and decently compact strings. In fact, I would just write "wrapper" procedures that take string inputs and handle the decode / encode / buffer / encrypt / decrypt together.
Re: Encyrpting data (like a password)
Posted: Fri Jul 01, 2011 4:42 pm
by purebuilt
I will check it out. It does not have to be all that secure, just obscured. The database is protected by security also.
I was looking for something like,
password = ecyrypt(pw,key)
password = decrypt(pw,key)
Thanks.
DB
Re: Encyrpting data (like a password)
Posted: Fri Jul 01, 2011 5:19 pm
by netmaestro
purebuilt, give this a try (password max length: 32 characters):
Code: Select all
Procedure$ EncryptPassword(password$, key$)
Protected passin$ = LSet(password$, 32, Chr(32)) ; Pad the password with spaces to make 32 characters
Protected keyin$ = LSet(key$, 16, Chr(32)) ; key for 128bit encryption needs length=16
Protected *encodedbinary = AllocateMemory(32) ; 32 bytes for encrypted binary result, see 2 lines down
Protected *encodedtext = AllocateMemory(64) ; Destination for Base64Encoder must be 33% larger- we double it
AESEncoder(@passin$, *encodedbinary, 32, @keyin$, 128, 0, #PB_Cipher_ECB) ; We don't encrypt the trailing zero so 32 bytes is enough
Base64Encoder(*encodedbinary, 32, *encodedtext, 64) ; Convert encrypted binary data to ascii for return
ProcedureReturn PeekS(*encodedtext) ; Return the completed ascii result
EndProcedure
Procedure$ DecryptPassword(password$, key$)
Protected keyin$ = LSet(key$, 16, Chr(32)) ; key for 128bit decryption needs length=16
Protected *encodedbinary = AllocateMemory(33) ; 32 bytes for data + one safety byte
Protected *decodedtext = AllocateMemory(33) ; 32 bytes for characters + one byte for terminating zero
Base64Decoder(@password$, Len(password$), *encodedbinary, 32) ; Convert the ascii encoded password back to binary
AESDecoder(*encodedbinary, *decodedtext, 32, @keyin$, 128, 0, #PB_Cipher_ECB) ; Convert the encrypted password back to original
ProcedureReturn Trim(PeekS(*decodedtext, 32)) ; Remove any trailing spaces and return result
EndProcedure
this$ = EncryptPassword("Holy Smoke, Batman! ", "somekey")
that$ = DecryptPassword(this$, "somekey")
Debug "Encrypted password: "+this$
Debug "Decrypted password: "+that$
It's actually reasonably strong, simple as it is. If the user puts more than 32 characters for the password, no error will happen but only the first 32 will count.
Re: Encyrpting data (like a password)
Posted: Fri Jul 01, 2011 7:27 pm
by purebuilt
Thanks... You're the best! Viva la PureBasic!!!!
DB
Re: Encyrpting data (like a password)
Posted: Fri Nov 18, 2011 7:10 pm
by Blue
@NetMaestro
Many, many thanks !
I've been using these encryption functions, in a similar way, for a long time, but it never occured to me to do...
Code: Select all
[...]
AESEncoder(@passin$, *encodedbinary, 32, @keyin$, 128, 0, #PB_Cipher_ECB) ; ...
Base64Encoder(*encodedbinary, 32, *encodedtext, 64) ; Convert encrypted binary data to ascii for return
[...]
That combination (and its inverse) makes coding so much simpler. I've just learned something important here.
Great. Thank you for sharing that code.
Re: Encyrpting data (like a password)
Posted: Fri Nov 18, 2011 9:01 pm
by jesperbrannmark
If you are going to transfer this over a public network, it could be smart to put some extra "salt" on the steak..
Put in something like the date today somewhere... So you know it changes every day.
Re: Encyrpting data (like a password)
Posted: Sat Nov 19, 2011 2:39 pm
by ultralazor
You use meta data and encrypt with the contained password, then check for meta data by decrypting with typed password. Using a cipher like AES it can only be brute forced..
Re: Encyrpting data (like a password)
Posted: Sat Jun 07, 2014 6:22 am
by rsts
Once again netmaestro, one of your fine contributions provides a perfect solution.
I realize I'm a bit late to the party, but just now had the need for something like this.
cheers
Re: Encyrpting data (like a password)
Posted: Sun Apr 20, 2025 12:44 pm
by dibor
netmaestro wrote: Fri Jul 01, 2011 5:19 pm
purebuilt, give this a try (password max length: 32 characters):
Code: Select all
Procedure$ EncryptPassword(password$, key$)
Protected passin$ = LSet(password$, 32, Chr(32)) ; Pad the password with spaces to make 32 characters
Protected keyin$ = LSet(key$, 16, Chr(32)) ; key for 128bit encryption needs length=16
Protected *encodedbinary = AllocateMemory(32) ; 32 bytes for encrypted binary result, see 2 lines down
Protected *encodedtext = AllocateMemory(64) ; Destination for Base64Encoder must be 33% larger- we double it
AESEncoder(@passin$, *encodedbinary, 32, @keyin$, 128, 0, #PB_Cipher_ECB) ; We don't encrypt the trailing zero so 32 bytes is enough
Base64Encoder(*encodedbinary, 32, *encodedtext, 64) ; Convert encrypted binary data to ascii for return
ProcedureReturn PeekS(*encodedtext) ; Return the completed ascii result
EndProcedure
Procedure$ DecryptPassword(password$, key$)
Protected keyin$ = LSet(key$, 16, Chr(32)) ; key for 128bit decryption needs length=16
Protected *encodedbinary = AllocateMemory(33) ; 32 bytes for data + one safety byte
Protected *decodedtext = AllocateMemory(33) ; 32 bytes for characters + one byte for terminating zero
Base64Decoder(@password$, Len(password$), *encodedbinary, 32) ; Convert the ascii encoded password back to binary
AESDecoder(*encodedbinary, *decodedtext, 32, @keyin$, 128, 0, #PB_Cipher_ECB) ; Convert the encrypted password back to original
ProcedureReturn Trim(PeekS(*decodedtext, 32)) ; Remove any trailing spaces and return result
EndProcedure
this$ = EncryptPassword("Holy Smoke, Batman! ", "somekey")
that$ = DecryptPassword(this$, "somekey")
Debug "Encrypted password: "+this$
Debug "Decrypted password: "+that$
It's actually reasonably strong, simple as it is. If the user puts more than 32 characters for the password, no error will happen but only the first 32 will count.
This code doesn't work anymore:(
[14:25:24] [COMPILER] Line 7: Base64Encoder(): Incorrect number of parameters.
Looks like Base64Decoder() and Base64Encoder() were changed.
Re: Encyrpting data (like a password)
Posted: Sun Apr 20, 2025 2:47 pm
by NicTheQuick
jesperbrannmark wrote: Fri Nov 18, 2011 9:01 pm
If you are going to transfer this over a public network, it could be smart to put some extra "salt" on the steak..
Put in something like the date today somewhere... So you know it changes every day.
When en/decrypting the initialization vector can be used as salt. Before encryption it can be generated using CryptRandomData() and then stored besides the encryted data. Here's a simple example that's meant for strings:
Code: Select all
EnableExplicit
UseSHA2Fingerprint()
UseCRC32Fingerprint()
Structure EncryptedData
iv.a[16]
bits.w
iterations.w
inputSize.l
crc32.l
*data.Byte[0]
EndStructure
Procedure.s EncryptString(string.s, passphrase.s, bits.i = 192, iterations.i = 100)
; Create cryptographic secure inititialization vector
Protected *iv = AllocateMemory(16)
If Not OpenCryptRandom()
DebuggerError("OpenCryptRandom failed.")
ProcedureReturn ""
EndIf
CryptRandomData(*iv, 16)
CloseCryptRandom()
; Derive encryption key from passphrase
Protected *key = AllocateMemory(bits / 8)
If Not DeriveCipherKey(passphrase, Base64Encoder(*iv, 16), iterations, *key, bits, #PB_Cipher_SHA2, 512)
DebuggerError("DeriveCipherKey failed.")
FreeMemory(*iv)
FreeMemory(*key)
ProcedureReturn ""
EndIf
; Pad string if needed
Protected inputSize.i = StringByteLength(string, #PB_UTF8)
If inputSize < 16
string + Space(16 - inputSize)
EndIf
Protected *input = UTF8(string)
Protected inputSizePadded.i = MemorySize(*input) - 1 ; ignore terminating null byte
Protected *output.EncryptedData = AllocateMemory(SizeOf(EncryptedData) + inputSizePadded)
If Not AESEncoder(*input, *output + SizeOf(EncryptedData), inputSizePadded, *key, bits, *iv, #PB_Cipher_CBC)
DebuggerError("AESEncoder failed")
FreeMemory(*iv)
FreeMemory(*key)
FreeMemory(*input)
FreeMemory(*output)
ProcedureReturn ""
EndIf
With *output
CopyMemory(*iv, @\iv, 16)
\inputSize = inputSize
\bits = bits
\iterations = iterations
\crc32 = Val("$" + Fingerprint(*input, inputSizePadded, #PB_Cipher_CRC32))
EndWith
Protected result.s = Base64Encoder(*output, inputSizePadded + SizeOf(EncryptedData))
FreeMemory(*iv)
FreeMemory(*key)
FreeMemory(*input)
FreeMemory(*output)
ProcedureReturn result
EndProcedure
Procedure.s DecryptString(encryptedString.s, passphrase.s)
; Expect the decoded data to be 20% less
Protected expectedInputSize.i = Len(encryptedString) * 4 / 5
Protected *input.EncryptedData = AllocateMemory(expectedInputSize)
Protected realInputSize.i = Base64Decoder(encryptedString, *input, expectedInputSize)
; Check encrypted data size for validity
If realInputSize < SizeOf(EncryptedData) + 16
DebuggerError("encryptedString seems to be too short.")
FreeMemory(*input)
ProcedureReturn ""
EndIf
Protected inputSizePadded.i = realInputSize - SizeOf(EncryptedData)
; Derive encryption key from passphrase
Protected *key = AllocateMemory(*input\bits / 8)
If Not DeriveCipherKey(passphrase, Base64Encoder(@*input\iv, 16), *input\iterations, *key, *input\bits, #PB_Cipher_SHA2, 512)
DebuggerError("DeriveCipherKey failed.")
FreeMemory(*input)
FreeMemory(*key)
ProcedureReturn ""
EndIf
Protected *output = AllocateMemory(inputSizePadded)
If Not AESDecoder(*input + SizeOf(EncryptedData), *output, inputSizePadded, *key, *input\bits, @*input\iv, #PB_Cipher_CBC)
DebuggerError("AESDecoder failed.")
FreeMemory(*output)
FreeMemory(*input)
ProcedureReturn ""
EndIf
FreeMemory(*key)
Protected crc32.l = Val("$" + Fingerprint(*output, inputSizePadded, #PB_Cipher_CRC32))
If crc32 <> *input\crc32
FreeMemory(*output)
FreeMemory(*input)
ProcedureReturn "[WRONG PASSPHRASE]"
EndIf
Protected result.s = PeekS(*output, *input\inputSize, #PB_UTF8 | #PB_ByteLength)
FreeMemory(*output)
FreeMemory(*input)
ProcedureReturn result
EndProcedure
Define encrypted.s = EncryptString("Hello World", "my passphrase", 256)
Debug encrypted
Debug DecryptString(encrypted, "wrong passphrase")
Debug DecryptString(encrypted, "my passphrase")