Yii2 Encryption generates different encryption data - encryption

I am using encryptByKey() for SSN and Account Number encryption in Yii2. The problem is that it generates different encrypted data for the same Account Number when I try to re-generate it.
I can't match it in the database like the following:
Customers::findOne(['account_number'=> Yii::$app->getSecurity()->encryptByKey($account_number, "someKeyHere")]);
Is there any encryption method available to generate same encrypted data every time I encrypt it?
Thanks,

Generally, that's the way encryption is supposed to work. It is sometimes called "ciphertext indistinguishability." Yielding the same ciphertext every time a given plaintext is encrypted undermines security by allowing attackers to analyze collections of ciphertext for patterns.
In this case, it looks like you only store one instance of the encrypted account number; you could argue that because the "message" is never repeated, cipher text indistinguishability is moot. That could lead you to justify the use of ECB mode (if your API offered it) or a HMAC (message authentication code, offered by the hashData() method) to compute a lookup key. If an attacker gets access to your database, there will only be one instance of each key, and nothing is revealed.
However, this is still insecure if an attacker can provide account numbers that your system encrypts. For example, an attacker could pose a legitimate user and provide a SSN during registration. If they choose a duplicate number, and then look in the database, their maliciously chosen encrypted value will match a legitimate record. Or, if the system rejects their account number because it is a duplicate, the attacker will know that it is a number in use by a legitimate user. This is called an oracle attack.
If you use an HMAC (or ECB mode encryption), you would have to design your application very carefully to prevent chosen plaintext and oracle attacks. And, candidly, if you are now encountering these ideas for the first time, there are probably many other gaps in your knowledge that will lead to easily exploited vulnerabilities in your application.

Related

Where do I store a hash securely on my Mac mini?

So I just got my first Computer with MacOS (never used MacOS, idk anything). I am trying to make a password manager which stores all my data (usernames, emails, passwords etc.) so I only need to remember one MasterPassword.
All the Data is AES encrypted with that MasterPassword and the hash of that Password is currently stored in a .txt file. Now I am thinking: What if someone just puts his own hash into that file and just logs into the program ?
How do I store this hash safely?
In general, the number one rule of crypto is "never roll your own crypto". (never write your own system to be secure when somebody else has already written one.) There are a number of reasons for this, but the most obvious is that even if you are very smart, an established package will have had more smart eyes on it to patch any security issues you might have missed.
If you want to safely store your data, use a password manager that is well-established.
If you want to make a password manager as a personal project though, here are some things to consider.
The most secure way to store a hash is to not store it at all. If you're AES encrypting your data, the way to verify that it has been decrypted is that the decrypted plaintext is correct. That way, you don't need to store anything regarding the password at all.
You want to salt your hashes so that common passwords do not lead to common hashes. The SHA-512 sum for password is 9151440965cf9c5e07f81eee6241c042a7b78e9bb2dd4f928a8f6da5e369cdffdd2b70c70663ee30d02115731d35f1ece5aad9b362aaa9850efa99e3d197212a. Here are the google search results for that string. If we instead hash password+EsistDerPascal K we get a string that returns no google search results. See the link for standard hashing techniques.
Use a proper cryptographic hash. While many things still use SHA-512 others have moved to bcrypt or other algorithms. If you're here from the future and Ubuntu isn't using SHA-512, don't use it.
You want your hash (and salt) to be only readable by users who should be able to use it. The easiest thing here is probably using chmod 600 to restrict read/write of the file to your user (or another user, or root).
This is an incomplete list and you should not rely upon any of the above to protect sensitive information.

DPAPI Key Storage and Restoration

In light of the upcoming GDPR regulations, the company I work for is looking at upgrading their encryption algorithms and encrypting significantly more data than before. As the one appointed to take care of this, I have replaced our old CAST-128 encryption (I say encryption but it was more like hashing, no salt and resulting in the same ciphertext every time) with AES-256 and written the tools to migrate the data. However, the encryption key is still hardcoded in the application, and extractable within a couple of minutes with a disassembler.
Our product is a desktop application, which most of our clients have installed in-house. Most of them are also hosting their own DBs. Since they have the entirety of the product locally, securing the key seems like a pretty difficult task.
After some research, I've decided to go with the following approach. During the installation, a random 256-bit key will be generated for every customer and used to encrypt their data with AES encryption. The key itself will then be encrypted with DPAPI in user mode, where the only user who can access the data will be a newly created locked down domain service account with limited permissions, who is unable to actually log in to the machine. The encrypted key will the be stored in an ACL-ed part of the registry. The encryption module will then impersonate that user to perform its functions.
The problem is that since the key will be randomly generated at install time, and encrypted immediately, not even we will have it. If customers happen to delete this account, reinstall the server OS, or manage to lose the key in some other manner, the data will be unrecoverable. So after all that exposition, here comes the actual question:
I am thinking of having customers back up the registry where the key is stored and assuming that even after a reinstall or user deletion, as long as the same user account is created with the same password, on the same machine, it will create the same DPAPI secrets and be able to decrypt the key. However, I do not know whether or not that is the case since I'm not sure how these secrets are generated in the first place. Can anyone confirm whether or not this is actually the case? I'm also open to suggestions for a completely different key storage approach if you can think of a better one.
I don't see the link with GDPR but let's say this is just context.
It takes more than the user account, its password and the machine. there is more Entropy added to the ciphering of data with DPAPI.
See : https://msdn.microsoft.com/en-us/library/ms995355.aspx#windataprotection-dpapi_topic02
A small drawback to using the logon password is that all applications
running under the same user can access any protected data that they
know about. Of course, because applications must store their own
protected data, gaining access to the data could be somewhat difficult
for other applications, but certainly not impossible. To counteract
this, DPAPI allows an application to use an additional secret when
protecting data. This additional secret is then required to unprotect
the data. Technically, this "secret" should be called secondary
entropy. It is secondary because, while it doesn't strengthen the key
used to encrypt the data, it does increase the difficulty of one
application, running under the same user, to compromise another
application's encryption key. Applications should be careful about how
they use and store this entropy. If it is simply saved to a file
unprotected, then adversaries could access the entropy and use it to
unprotect an application's data. Additionally, the application can
pass in a data structure that will be used by DPAPI to prompt the
user. This "prompt structure" allows the user to specify an additional
password for this particular data. We discuss this structure further
in the Using DPAPI section.

coldfusion salting my hash

In ColdFusion, What is the best best of doing a user login password comparison with the database that will encrypt the password between the client and server?
I noticed there's a javascript version at http://pajhome.org.uk/crypt/md5/index.html
but what can be done for users without javascript enabled?
These points are not specific to coldfusion, but I feel I must state them:
Do the hash server-side.
The point of hashing is to make it really hard to figure out what to send the server in order to produce the string it matches with the DB. If you just match the string given by the client with the DB entry, you're defeating the purpose.
Don't use MD5.
It's broken. There are ways to defeat it. Don't use it.
If you're worried about the password being exposed on the way to the server, use TLS.
TLS is designed for making communications between a client and a server opaque to anyone else. The biggest problem with it is the recent BEAST attack, which won't work if you implement it right.
Use a secure hash like SHA-256.
As far as we know, SHA-256 is pretty damn secure. The best known attack on it reduces the time complexity by 2 bits, which doesn't make an attack practical.
Use a random salt, unique to each user.
A precomputed rainbow table for 2^50-bit space would take 256 petabytes of storage, and one for 2^256 space would take an enormous amount more. However, due to the Birthday Problem, it's conceivable that some of your users' accounts could be compromised if you do not salt their hashes.
Hash multiple times. On the order of thousands of times.
If your DB is compromised, a hash might mean that your average user's password is found in years. If you has thousands of times, that would mean thousands of years.
Some additional points, to address misconceptions it looks like you have:
A cryptographic hash is one-way. You can't decrypt it. If you find a practical way to decrypt it, then you will become rich and (in)famous.
Standard HTTP is not secure. Anyone can eavesdrop and intercept your password that is being POSTed in plaintext, or hashed. If your server doesn't demand an encrypted connection for sensitive data, you're asking for a replay attack (http://en.wikipedia.org/wiki/Replay_attack).
You can make your own SSL certificate. If you're worried about your users seeing "this SSL Cert is self signed! Oh noes!" and being scared off, either do without and take the risk, or cough up the cash.

Best Practice: Protecting Personally Identifiable Data in a ASP.NET / SQL Server 2008 Environment

Thanks to a SQL injection vulnerability found last week, some of my recommendations are being investigated at work. We recently re-did an application which stores personally identifiable information whose disclosure could lead to identity theft. While we read some of the data on a regular basis, the restricted data we only need a couple of times a year and then only two employees need it.
I've read up on SQL Server 2008's encryption function, but I'm not convinced that's the route I want to go. My problem ultimately boils down to the fact that we're either using symmetric keys or assymetric keys encrypted by a symmetric key. Thus it seems like a SQL injection attack could lead to a data leak. I realize permissions should prevent that, permissions should also prevent the leaking in the first place.
It seems to me the better method would be to asymmetrically encrypt the data in the web application. Then store the private key offline and have a fat client that they can run the few times a year they need to access the restricted data so the data could be decrypted on the client. This way, if the server get compromised, we don't leak old data although depending on what they do we may leak future data. I think the big disadvantage is this would require re-writing the web application and creating a new fat application (to pull the restricted data). Due to the recent problem, I can probably get the time allocated, so now would be the proper time to make the recommendation.
Do you have a better suggestion? Which method would you recommend? More importantly why?
Encryption in SQL is really only good for securing the data as it rests on the server, although that doesn't mean that it is unimportant. When you mention that a prime concern is injection attacks or the likes, my concern would be whether or not the database uses a single account (SQL or otherwise) to connect to the database, which would be common for a public internet site. If you use integrated authentication, or connect to SQL using the same credentials supplied to the application, then SQL's encryption might work fine.
However, if you're using a single login, SQL's encryption is going to manage encrypting and decrypting the data for you, based on your login. So, if your application is compromised, SQL may not be able to protect that data for you, as it implicitly decrypts it and doesn't know anything is wrong.
You may want to, as you suggested, encrypt/decrypt the data in the application, and store as bytes in the database. That way you control who can decrypt the data and when (for example, you could assign the key to decrypting this data to those few employees you mentioned that are in a specific role). You could look into Microsoft's Security Application Block, or Bouncy Castle, etc. for good encryption utilities. Just be careful about how you manage the key.
Update:
Although you could potentially use two connection strings: one normal, with no rights to the encrypted data, and one that has the key and the rights to the data. Then have your application use the appropriate connection when the user has the rights. Of course, that's pretty kludgy.
Some practices that we follow:
Never use dynamic sql. It's completely unnecessary.
Regardless of #1, always parameterize your queries. This alone will get rid of sql injection, but there are lots of other entry points.
Use the least priviledged account you can for accessing the database server. This typically means the account should NOT have the ability to run ad hoc queries (see #1). It also means that it shouldn't have access to run any DDL statements (create, drop, ..).
Don't trust the web application, much less any input received from a browser. Sanitize everything. Web App servers are cracked on a regular basis.
We also deal with a lot of PII and are extremely strict (to the point of paranoia) on how the data is accessed and by whom. Everything that comes through the server is logged. To make sure this happens we only allow access to the database through stored procedures. The procs always test to see if the user account is even authorized to execute the query. Further they log when, who, and what. We do not have any mass delete queries at all.
Our IDs are completely non-guessable. This is for every table in the system.
We do not use ORM tools. They typically require way too much access to the database server to work right and we just aren't comfortable with that.
We do background checks on the DBA's and our other production support people every 6 months. Access to production is tightly controlled and actively monitored. We don't allow contractors access to production for any reason and everything is code reviewed prior to being allowed into the code base.
For the encrypted data, allow specific users access to the decryption keys. Change those keys often, as in once a month if possible.
ALL data transfer between machines is encrypted. Kerberos between servers and desktops; SSL between IIS and browsers.
Recognize and architect for the fact that a LOT of data theft is from internal employees. Either by actively hacking the system, actively granting unauthorized users access, or passively by installing crap (like IE 6) on their machines. Guess how Google got hacked.
The main question in your situation is identifying all of the parts that need access to the PII.
Things like how does the information get into your system? The main thing here is where does the initial encryption key get stored?
Your issue is key management. No matter how many way's you turn the problem around, you'll end up with one simple elementary fact: the service process needs access to the keys to encrypt the data (is important that is a background service because that implies it cannot obtain the root of the encryption hierarchy key from a human entered password whenever is needed). Therefore compromise of the process leads to compromise of the key(s). There are ways to obfuscate this issue, but no ways to truly hide it. To put this into perspective though, only a compromise of the SQL Server process itself could expose this problem, something which is significantly higher bar than a SQL Injection vulnerability.
You are trying to circumvent this problem by relying on the public key/private key asymmetry and use the public key to encrypt the data so that it can only be decrypted by the owner of the private key. So that the service does not need access to the private key, therefore if compromised it cannot be used to decrypt the data. Unfortunately this works only in theory. In the real world RSA encryption is so slow that is cannot be used for bulk data. This is why common RSA based encryption scheme uses a symmetric key to encrypt the data and encrypts the symmetric key with the RSA key.
My recommendation would be to stick with tried and tested approaches. Use a symmetric key to encrypt the data. Use an RSA key to encrypt the symmetric key(s). Have SQL Server own and control the RSA private key. Use the permission hierarchy to protect the RSA private key (really, there isn't anything better you could do). Use module signing to grant access to the encryption procedures. This way the ASP service itself does not even have the privileges to encrypt the data, it can only do so by the means of the signed encryption procedure. It would take significant 'creative' administration/coding mistakes from your colleagues to compromise such a scheme, significantly more than a mere 'operator error'. A system administrator would have an easier path, but any solution that is designed to circumvent a sysadmin is doomed.

storing credit card info

So I would like to modify a PHP / MySQL application in order to store credit card but not cvv and bank account info securely. PCI DSS require 1024 RSA/DSA. A small number of users will be given private key in order to decrypt the batch file of account info for submission to payment processors monthly. I'm unclear if it is possible to have a system that would allow the users who have signed in with normal 8 digit passwords to modify their own account info securely. It seems that this is not possible, and the encryption should be one-way (ie each user -> admins; never allowing user to decrypt their own info again), with account info never exposed back to users even over SSL connections. Or is there a proper and easy way to do this that I'm unaware of that is PCI DSS compliant?
PCI DSS does not require 1024 bit RSA to encrypt. Older versions of the specification mentioned AES and 3DES by name, but I believe newer versions just specify strong encryption. Most people are using AES 256.
Encrypting data at-rest with an asymmetric algorithm doesn't really work. Symmetric algorithms work best. This allows the application to access the card data when it needs to. This doesn't mean you have to show the data to the user ever again, it just means the data is there when you need to get to it. If you're storing credit card authorization information, you'll usually need the card number for settlement. (It really depends on the features your processor has. Some of the small-business level processors store the card for you, but this is infeasible for large scale processors like Paymentech and FDMS.)
The problem is that you will have to rotate your encryption keys periodically. This is usually what screws everyone up. If you roll your own encryption, you need to make sure that you can specify n number of keys that are accessible for as long as there is data encrypted with those keys. At any point in time, only one of those keys should be used for encryption. Unless you have a deep understanding of crypto and key management in terms of PCI, you might want to go with a commercial offering. Yes, these are expensive, but you have to determine the best course with a build or buy decision making process.
Ingrian (now SafeNet) has a decent offering for a network HSM. It will manage the keys for you and do the cryptographic operations. It may also be possible to use their DB level encryption integration so that you don't have to change your application at all. (Though DB level encryption is dubiously secure in my opinion.)
This is a very deep subject; I've done a lot with PCI and suggest you hire someone to guide you through doing it properly. You'll spend a lot of money on false starts and redoing work, so get an auditor involved early to at least asses what you need and tell you how to implement the security properly.
You may have an easier time if you differentiate between data storage, access, and transmission.
Storage requires strong reversible encryption; the data is not useful unless you can retrieve it.
Access requires a user or process to authenticate itself before it is permitted to decrypt the data. Here's an example of a mechanism that would accomplish this:
Store the data with a secret key that is never directly exposed to any user. Of course, you'll need to store that key somewhere, and you must be able to retrieve it.
When each user chooses a password, use the password to encrypt a personal copy of the private key for that user. (Note: even though you're encrypting each copy of the key, security issues may arise from maintaining multiple copies of the same information.)
Do not store the user's password. Instead, hash it according to standard best practices (with salt, etc.) and store the hash.
When a user provides a password to log in, hash it and compare to your stored value. If they match, use the (plainitext) password to decrypt the key, which is then used to decrypt the actual data.
Transmit the data through a secure connection, such as SSL. It's reasonable (perhaps required) to allow users to access (and modify) their own data, as long as you continue to follow best practices.
Comments:
An 8-digit password implies a key space of 108 ~ 227 = 27 bits, which by today's standards is fairly terrible. If you can't encourage longer (or alphanumeric) passwords, you may want to consider additional layers.
One advantage to the multiple-layer strategy (user provides a password that is used to encrypt the "actual" key) is that you can change the encryption key transparently to the user, thereby satisfying any key-rotation requirements..
The standard admonition whenever you're designing a security solution is to remember that DIY security, even when following standards, is risky at best. You're almost always better off using an off-the-shelf package by a reputable vendor, or at least having a trained, certified security professional audit both your strategy and your implementation.
Good luck!

Resources