I couldn't find this information anywhere on here or on Google, so quick question: When using openssl_encrypt should I be using the actual cipher names (i.e. "bf-cbc") or can I use the aliases (i.e. "blowfish")?
FWIW, I'm using PHP 5.6.34.
Bonus question: According to the PHP documentation, some of the methods have been proven to be weak, so which one is the strongest or which are the strongest amongst the methods that remain?
Don't use the aliases, be as specific as you can with the cipher you intend to use.
AES is probably the most appropriate algorithm to use here. The mode you use is important as well. With this in mind, I would prioritize the following, in order:
aes-*-gcm
aes-*-ctr
aes-*-cbc
Where * is obviously one of 256/192/128. Remember that each of the above modes has different requirements for it to be secure. GCM needs a 96-bit nonce, and no additional authentication. CTR usually uses a 128-bit nonce and needs a MAC to be secure. Using the same nonce and key for two different messages in GCM or CTR mode will expose the plaintext, so don't ever do that. CBC needs a 128-bit IV and a MAC to be secure.
I suggest you view the code in this repository for an example of secure encryption in PHP.
Related
I have a client who requires all of the data stored in the MySQL database to be encrypted with 128-bit encryption.
Assuming that before all data is inserted into the DB, a PHP function is run to encrypt it. Then, when I pull the data from the database, I run a decryption function to spit out the original text/info.
Can someone point in me in the right direction. I understand that the functions will use a shared/common key to encrypt and decrypt, but what makes it 128bit? Are there prebuilt functions in PHP that do this?
Appreciate any suggestions.
Scott
Typically, "128-bit encryption" refers to symmetric encryption using a 128-bit key. AES-128 is an excellent choice for an encryption algorithm.
You will also need to choose a mode of operation: CBC, CFB, OFB and CTR are all good choices if you only need privacy, but if you also want to protect the data against tampering, you should use an authenticated encryption mode such as EAX. Do not use ECB mode unless all your records are shorter than a single AES block (also 128 bits), and preferably not even if they are.
Depending on the mode you've chosen, you will typically also need to generate an initialization vector (IV) for each record, which should be a unique and unpredictable random cipher block (128 bits for AES). There are many ways to generate one, but two good ones (recommended by NIST) are either using the output of a cryptographically secure pseudorandom number generator or encrypting a unique ID in ECB mode (this is one of the rare cases for which it is OK to use). Depending on the crypto library you're using, it may take care of this for you. Please do note that, if you ever change the encrypted data in a record, you should always change the IV too.
As the other answers note, mcrypt is a good choice for a crypto library if you're using PHP.
I hope here is your solution. Refer two functions encrypt and decrypt on the page and grab the idea.
yes.You need to study about the classes/API using for encryption in which they must mentioned that.They are also dependent on algoritham that which type of algorithm you are using.Please follow this link to learn more about this.Here is a breif explaination about encryption.You can found a sample of code here but mycrypt is more recommended
Here's a theoretical one that not only applies to PHP, but probably to more languages.
Let's say that I encrypt a string with the mcrypt library using and the AES-256 cipher. The string, encrypted, would now look similar to þøÆ{”ò(ü´îÚÜÇW¹ËŸK¯L‘rø?ª¶!JF£º+Œ’Ú'‚.
If the encryption key would change between the events of decryption and encryption, the result of the decryption would obviously be worthless.
Since an encrypted string contains, at least to me, random chars, It wouldn't be easy to run some sort of test on it to ensure that it is in encrypted/decrypted state.
I've spent some time thinking. How can I test that a string has been properly decrypted?
What if I appended a small prefix to the original string before encrypting it in the first place, and then removed this prefix upon decryption. If this prefix wasn't found, it would be safe to say that the decryption has failed.
Would this be an appropriate way to handle this?
To test data integrity you want a Message Authentication Code (MAC).
There are a few stand-alone MAC algorithms, which look like a hash function with a key. The very standard MAC algorithm is HMAC (which uses a hash function).
Since you also encrypt the data, you will want to use an encryption mode with a builtin MAC; there are a few such modes, such as GCM or EAX. Those modes apply to a block cipher, usually the AES.
Adding a known prefix or suffix to the data before encryption is a homemade MAC. MACs are subtle and error prone. For instance, if you add a CRC32 and then encrypt with a stream cipher (or a block cipher in CTR mode), then you are reproducing one of the seven capital sins of WEP (see section 4 in particular, for the CRC32-as-MAC issue). Basically your integrity check is no longer resistant to active attacks; you are only detecting innocent mistakes, such as using the wrong key.
(Unfortunately, it seems that MCrypt does not support any combined encryption/MAC mode. PHP itself, when compiled with the --with-mhash option, provides the mhash() function which implements both raw hashing, and HMAC.)
How can I test that a string has been properly decrypted?
The "small prefix" idea should be fine; also the excellent idea by #CodeInChaos. Other than that, storing the string in some defined format (like serialize() or json_encode()) and failing to restore it (unserialize(), json_decode()) would be indication of a broken decryption as well.
I'll keep this short and simple. As part of PHP's mcrypt library there are 40 or so possible ciphers, see here.
Not knowing much about encryption myself, I'm working under the assumption regardless of the cipher used, the data when decrypted is identical as the data encrypted (otherwise what's the point right?)
I need to encrypt and then decryption either an array or serialised standard object. I've browsed a couple examples online of the basic implementation of the mcrypt library and noticed that each example used a different cipher. It got me wondering if there was any significance to this, or simply personal preference?
My question is, is there any significant differences between these ciphers I should be concerned with knowing that
I'll be encrypting/decrypting is an either an array or serialised standard object, and contain relatively little data.
This operation will be fairly uncommon so speed isn't a massive issue, anywhere in the range on < 2s is acceptable.
The encrypted string will need to be stored in a cookie and transmitted via url query string (so there are limitations on length and character set)
Note
I'm not after a debate about whether I should be using a hash or hmac. Encryption is necessary and the correct option for this problem.
Any reasonable cipher encrypts/decrypts between plaintext/ciphertext given the correct key.
There are huge differences to which cipher you choose. Be it block length, key length and/or general security. For instance, you should never use DES because it only uses a 56-bit key. Similar for other ciphers on the list you refer to. Before using any cipher always read up on it and determine whether it is a good cipher for your context.
But I can't go into detail about every cipher on your list here. :-)
I personally like AES (Rijndael) which takes three sizes of keys 128, 192 and 256 bits. The best known attack is faster than a brute-force attack but is still infeasible. It is fast, too (actually Intel included machine instructions for AES in Westmere and Sandy Bridge).
Serpent and Twofish are also good ciphers. Serpent came second to Rijndael and Twofish came third (I think it was) in the AES contest some years back.
I have a PHP app that needs to run bash scripts, and provide a username & password (for remote systems).
I need to store these credentials somewhere that is accessible by my PHP (web) app.
The logical place is the database (currently MySQL, but will be agnostic).
The problem with the "standard" way of hashing and storing the credentials, is that it is not reversible. I have to be able to get the credentials out as unencrypted clear text, to be able to insert the data into bash scripts.
Does anyone have any suggestions for a secure way to go about this ?
I thought maybe PKI'ing the credentials, and storing the result in the DB. Then use the private key to unencrypt (PHP can do that). Store the scripts to do this outside the web root.
Any thoughts much appreciated.
First, to state the (hopefully) obvious, if you can in any way at all avoid storing usernames and passwords do so; it's a big responsibility and if your credential store is breached it may provide access to many other places for the same users (due to password sharing).
Second, if you must store credentials prefer rather to stored passwords using a non-reversible, salted cryptographic hash, so if you data is compromised the passwords cannot easily be reverse-engineered and there's no need to store a decryption key at all.
If you must store decryptable credentials:
Choose a good encryption algorithm - AES-256, 3DES (dated), or a public key cipher (though I think that's unnecessary for this use). Use cryptographic software from a reputable trustworthy source - DO NOT ATTEMPT TO ROLL YOUR OWN, YOU WILL LIKELY GET IT WRONG.
Use a secure random generator to generate your keys. Weak randomness is the number one cause of encryption related security failures, not cipher algorithms.
Store the encryption/decryption key(s) separately from your database, in an O/S secured file, accessible only to your applications runtime profile. That way, if your DB is breached (e.g. through SQL injection) your key is not automatically vulnerable, since that would require access to to the HDD in general. If your O/S supports file encryption tied to a profile, use it - it can only help and it's generally transparent (e.g. NTFS encryption).
If practical, store the keys themselves encrypted with a primary password. This usually means your app. will need that password keyed in at startup - it does no good to supply it in a parameter from a script since if your HDD is breached you must assume that both the key file and the script can be viewed.
For each credential set, store a salt (unencrypted) along with the encrypted data; this is used to "prime" the encryption cipher such that two identical passwords do not produce the same cipher text - since that gives away that the passwords are the same.
If the username is not necessary to locate the account record (which in your case it is not), encrypt both the username and password. If you encrypt both, encrypt them as one encryption run, e.g
userAndPass=(user+":"+pass);
encryptInit();
encrypt(salt);
encrypt(userAndPass);
cipherText=encryptFinal();
and store the singular blob, so that there is less occurrence of short cipher texts, which are easier to break, and the username further salts the password.
PS: I don't program in PHP so cannot comment on suitable crypto s/w in that environment.
You'll need to look into good 2 way cryptographic methods, and my general rule of thumb is:
If you implement your own cryptographic code you will fail.
So, find a good implementation that is well verified, and utilize that.
There is probably some good info here:
http://phpsec.org/library/
Check this library: PECL gnupg it provides you methods to interact with gnupg. You can easily encrypt and decrypt data, using safe public-key cryptographic algorithms.
I would suggest you not store the passwords, but use passwordless ssh connection from the host to the remote system by generating a ssh key and storing your public key in the remote system's authorized_keys file. Then you would only need to establish connectivity during configuration. Admittedly not quite answering your question, but storing passwords in a reversible form is a slippery slope to a security breach imho, although I am sure smarter brains than mine can make it safe.
One easy way to get started is to use mysql's ENCODE() and DECODE() functions. I don't know what algorithm is used underneath, but it's easy enough to use:
INSERT INTO tbl_passwords SET encoded_pw = ENCODE('r00t', 'my-salt-string');
and
SELECT DECODE(encoded_pw, 'my-salt-string') FROM tbl_passwords;
If you go the PKI, and I would, make sure you safe guard your private keys! The strong encryption provided by PKI is only as secure as your keys.
I think you're on target. Look at GPG for a good, open encryption library
It looks like you pretty much have two methods of doing this:
1) Like you suggested use an encryption algorithm or algorithms which can then be decrypted and used for authentication in your scripts. You can use the MCrypt library in PHP to accomplish this.
2) Depending on the required level of security and your script's level of vulnerability, you could use a secure hash, key, or some other hard to guess unique identifier that you can use to hijack each user's account within the confines of the script.
As many stated you scenario requires that you encrypt username and password. I would recommend that you check out the mcrypt extension of php for encryption/decryption.
I think I am going to investigate compiling a PHP script with the credentials embedded, on the fly, from the web app.
I would ask for the credentials (for a given use), then create and compile a new PHP script, for this use only. That way, the script will only do what I need, and should not be "readable". I think this sounds like the safest way to do this.
Will try using Roadsend. http://www.roadsend.com/
Just to follow up on the suggestion to use MySQL encode and decode functions, the manual is vague on just how these work:
The strength of the encryption is based on how good the random generator is. It should suffice for short strings.
But what I'd suggest is that you can instead use the built-in MySQL 5.0 AES functions; AES_ENCRYPT() and AES_DECRYPT()
SELECT AES_ENCRYPT('secret squirrel', '12345678') AS encoded
=> ØA;J×ÍfOU»] É8
SELECT AES_DECRYPT('ØA;J×ÍfOU»] É8', '12345678') AS decoded
=> secret squirrel
These use 128-bit AES which should be strong enough for most purposes. As others commented, using a salt value and a key with a high entropy is a good practice.
For PHP, it is important to note that AES encryption is implemented via MCRYPT_RIJNDAEL functions. Don't go paying for a non-open implementation when PHP has them available.
See the PHP page discussing available ciphers for more information.
I would like to encrypt strings which could potentially only be about three or four characters but run to about twenty characters. A hashing function (md5, sha1, crypt etc) is not suitable as I would like to be able to decrypt the information as well. The mcrypt extension has a thoroughly daunting array of possibilities.
Does anyone have any ideas about the best way to safely encrypt short strings and why? Does anyone have any links to any material introducing a casual programmer to practical encryption scenarios?
I like to use GnuPG for anything that needs to be encrypted on a server and then possibly decrypted either on the server or on another server (which is usually my case). This allows for an extra level of security since in my scenario the encrypting server doesn't have the key to decrypt the data. It also allows for easier manual decryption. There are a few good wrappers available for various languages (another advantage), one for PHP is GnuPGP PHP Class.
mcrypt is linked into most builds of PHP by default. It contains all the primitives you're likely to need. Without knowing more about what you're encrypting, what your threat model is, etc, it's hard to give concrete recommendations on what algorithm, mode of operation, etc to use.
One thing I can say for certain: With short text strings, it's more vital than ever that you MUST use a unique, random Initialization Vector. Otherwise, it's trivial for someone to mount a variety of attacks against the encrypted data.
I highly recommend the suggestions of Chris Kite. Without knowing more about what you're doing, why, and the threats you anticipate needing to protect against AES-128 is likely sufficient. The ability to use symmetric encryption is great for a standalone app that will be both the decryptor and encryptor of data. As both Chris Kite and Arachnid said, due to the small size of your data it's advised that you pad the data and use a random Initialization Vector.
Update: As for why.... if the data is small enough, and the IV can be predicted, it's possible to brute force the plain-text by generating cipher-text for every combination of plain-text with the known IV and matching it up to the captured cipher-text. In short, this is how rainbow tables work.
Now if you're going to encrypt on one server and decrypt on another I'd go with the suggestions of pdavis. By using an asymmetric method you're able to separate the encryption keys from the decryption keys. This way if the server that encrypts data is compromised, the attacker is still unable to decrypt the data.
If you're able to, it'd help the community to know more about your use case for the encryption. As I mentioned above, having a proper understanding of plausible threats is key when evaluating security controls.
I agree with Chris Kite - just use AES 128, this is far sufficient.
I don't know exactly your environment, but I guess you're transmitting the data somehow through the internet.
Don't use ECB, this will always produce the same result for the same plain text.
CBC mode is the way to go and don't forget a random initialization vector. This vector has to be communicated with the cipher text and can be sent in the clear.
Regarding your data, since AES is a block cipher, the outcome is always a multiple of the block size. If you don't want to let the observer know if your data is short or long, add some padding to extend it up to the maximum expected size.
If you want to encrypt and decrypt data within an application, you most likely want to use a symmetric key cipher. AES, which is the symmetric block encryption algorithm certified by the NSA for securing top secret data, is your best choice. There is a pure-PHP implementation available at www.phpaes.com
For your use it sounds like AES128 is sufficient. You will want to use CBC mode with a random initialization vector, or else the same data will always produce the same ciphertext.
Choosing the right encryption algorithm is a good first step, but there are many factors to a secure system which are hard to get right, such as key management. There are good resources out there, such as Applied Cryptography by Bruce Schneier, and Security Engineering by Ross Anderson (available for free online).
Does it matter if anybody can decrypt it? If you're just trying to obfuscate it a little, use ROT13. It's old school.
Any one-way encryption algorithm such as Blowfish will do, I guess. Blowfish is fast and open. You can use Blowfish through the crypt() function. AFAIK there are no encryption algorithm that work especially well on small strings. One thing to be aware of though is that brute-forcing such small strings will be very easy. Maybe you should encrypt the string along with a 'secret' salt value for additional security.
You can use the general programming ideas without relying in built in encryption/decription functions Example create a function call it
function encryptstring($string) {
$string_length=strlen($string);
$encrychars="";
/**
*For each character of the given string generate the code
*/
for ($position = 0;$position<$string_length;$position++){
$key = (($string_length+$position)+1);
$key = (255+$key) % 255;
$get_char_to_be_encrypted = SUBSTR($string, $position, 1);
$ascii_char = ORD($get_char_to_be_encrypted);
$xored_char = $ascii_char ^ $key; //xor operation
$encrypted_char = CHR($xored_char);
$encrychars .= $encrypted_char;
}
/**
*Return the encrypted/decrypted string
*/
return $encrychars;
}
On the page with link to include the id's required to be encrypted
/**
*While passing the unique value to a link
*Do the following steps
*/
$id=57;//or if you are fetching it automatically just pass it here
/**
*For more security multiply some value
*You can set the multiplication value in config file
*/
$passstring=$id*346244;
$encrypted_string=encryptstring($passstring);
$param=urlencode($encrypted_string);
/**
*Derive the url for the link
*/
echo 'something' ;
On the target file that get opened after the link is clicked
/**
*Retriving the value in the target file
*Do the following steps
*/
$fetchid=$_GET['aZ98#9A_KL'];
$passstring=urldecode(stripslashes($fetchid));
$decrypted_string= encryptstring($passstring);
/**
*Divide the decrypted value with the same value we used for the multiplication
*/
$actual_id= $decrypted_string/346244;