Encyrpting data (like a password)

Just starting out? Need help? Post your questions and find answers here.
User avatar
purebuilt
User
User
Posts: 46
Joined: Sun Dec 17, 2006 5:30 pm
Location: Milwaukee, WI, USA

Encyrpting data (like a password)

Post 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
- DB
Foz
Addict
Addict
Posts: 1359
Joined: Tue Nov 13, 2007 12:42 pm
Location: Manchester, UK

Re: Encyrpting data (like a password)

Post 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.
User avatar
purebuilt
User
User
Posts: 46
Joined: Sun Dec 17, 2006 5:30 pm
Location: Milwaukee, WI, USA

Re: Encyrpting data (like a password)

Post 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
- DB
Foz
Addict
Addict
Posts: 1359
Joined: Tue Nov 13, 2007 12:42 pm
Location: Manchester, UK

Re: Encyrpting data (like a password)

Post 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
User avatar
ultralazor
Enthusiast
Enthusiast
Posts: 186
Joined: Sun Jun 27, 2010 9:00 am

Re: Encyrpting data (like a password)

Post 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
so many ideas so little time..
User avatar
kenmo
Addict
Addict
Posts: 2043
Joined: Tue Dec 23, 2003 3:54 am

Re: Encyrpting data (like a password)

Post 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.
User avatar
purebuilt
User
User
Posts: 46
Joined: Sun Dec 17, 2006 5:30 pm
Location: Milwaukee, WI, USA

Re: Encyrpting data (like a password)

Post 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
- DB
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Encyrpting data (like a password)

Post 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.
BERESHEIT
User avatar
purebuilt
User
User
Posts: 46
Joined: Sun Dec 17, 2006 5:30 pm
Location: Milwaukee, WI, USA

Re: Encyrpting data (like a password)

Post by purebuilt »

Thanks... You're the best! Viva la PureBasic!!!!

DB
- DB
User avatar
Blue
Addict
Addict
Posts: 966
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re: Encyrpting data (like a password)

Post 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.
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
jesperbrannmark
Enthusiast
Enthusiast
Posts: 536
Joined: Mon Feb 16, 2009 10:42 am
Location: sweden
Contact:

Re: Encyrpting data (like a password)

Post 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.
User avatar
ultralazor
Enthusiast
Enthusiast
Posts: 186
Joined: Sun Jun 27, 2010 9:00 am

Re: Encyrpting data (like a password)

Post 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..
so many ideas so little time..
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Encyrpting data (like a password)

Post 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
dibor
Enthusiast
Enthusiast
Posts: 160
Joined: Wed May 20, 2020 5:19 pm
Location: The 3rd planet in the Solar System
Contact:

Re: Encyrpting data (like a password)

Post 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.
Mac Studio M1Max, PB 6.12 Arm64 and x64.
Macbook Air M2, PB 6.12 Arm64 and x64.
Windows 10, PB 6.12 x64 and x86.
User avatar
NicTheQuick
Addict
Addict
Posts: 1519
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Encyrpting data (like a password)

Post 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")
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Post Reply