The safest alternative to hashing credit card numbers to use the hash as a fingerprint?

The same question was asked here in 2014, but since a lot has changed since then, I would like to get feedback from experts on the latest best practices.

The problem

We have to hash credit card numbers in order to use them as fingerprints. We strive for the same strategy that Braintree uses according to John Downey's answer (the accepted answer), I quote:

“In the Braintree API, we offer a unique number identifier for a
Credit card. This identifier is a random opaque token that is always used
This also applies to the card number stored in our system. The seed for it
The number varies depending on the retailer in our system, so you cannot compare them
them about dealers.

When a new card arrives, we look it up
Compare it to a hash + salted column. If it matches the existing one
Column we know we can return the same unique number identifier. If it
does not match any existing data set, we use a cryptographically secure one
Pseudo random number generator for creating a new unique number
Identifier and make sure that it doesn't conflict with an existing one.

This
So the hash + salted value never leaves our backend, but we can
They also offer a merchant the opportunity to clearly identify saved loans
Cards."

The entire PCI compliance side is known and covered. We are currently dealing with the hashing part. Let us make it clear that the hashes must be vendor-specific so that salting with a vendor-specific secret key seems to be a good option (we are also aware of the problem of securely managing secret vendor keys). In this way the merchant can check whether two customers are using the same card number. So far we have considered the following alternatives:

  1. Use HMAC with the vendor-specific key as the secret cryptographic key. For the cryptographic hash function, we have to use a cryptographically secure one, so we chose SHA3. Then, however, we found that SHA3 can act as an HMAC. As explained here, the nested HMAC construction is not required.

  2. Hash the card number with SHA3 using the dealer-specific key. This seemed like a good option as long as you use the strongest version of SHA3 and a sufficiently long key. But then our concern about brute force attacks in the event of the theft of the database went away. After doing some research, we found that re-hashing the resulting hash times would help slow down the attacker's task and, at best, even make it impossible as long as it doesn't slow down our service. So we decided to do it and hashed our hash n times. But then we were curious about exactly how re-hashing increases security, and found that re-hashing itself is a good idea to implement your own non-standard hashing scheme without understanding what functions such a scheme needs, to be sure is not. A better option is a hashing algorithm that does a new hashing like PBKDF2, Scrypt or Argon2id.

  3. Use PBKDF2 to derive a key from the card number salted with the merchant-specific key, set a large number of iterations, and select SHA3 as a hash function.

  4. Use Argon2id, the current winner and recommendation of the password hashing contest, with the right parameters for time, memory, and Threads However, we are not yet sure how to set these parameters correctly. It would be very helpful to read your comments about it.

We are discussing between options 3 and 4, on the one hand PBKDF2 seems to be more widespread, on the other hand there are several resources that claim that it is no longer safe for today's hardware capacity and we strongly recommend the use of Argon2id.

What strategy would you use for this scenario? What shortcomings do you see in the previous options? Would you choose PBKDF2 or Argon2id?

Hash – user password authentication and password cracking – multiple rounds of hashing

Why can't John the Ripper crack hash passwords on multiple rounds of hashing? (Basically several rounds of hashes).
On the other hand, however, the system can authenticate a user even if passwords are stored using multiple hashing. how does it do that
is that John the Ripper can only crack 1 level of hashed password. and the system simply adapts the hash to the database or something?

java – Secure hashing of passwords

Before we even get to the parameters, there are a few security holes.

private char() password;

By storing the plaintext password in an instance field, it can be recognized from memory images over a longer period of time. The field does not have to be an instance field since it is only used in the hash Method.

public void hash(String rawPassword) {

The transfer of a plain text password as a string parameter makes safe disposal impossible. Passing passwords must be character arrays and must be deleted immediately when they are no longer needed.

public void destroy() {

You have the right idea that the class of confidential data has to be deleted, but here you have deleted the responsibility of the caller, while the data to be deleted is completely irrelevant to the caller. You should avoid having to rely on other people to handle sensitive data. Someone will forget to call destroy() because it's not something that needs to be done in a garbage collection environment. At least you could do it Closeable Therefore, there are some general contractual indications that the class needs to be cleaned up. However, it is better to write the classes so that no external cleanup is required.

private int ammountOfBytes = 64;
private int keyLength = 512;
private int iterations = 100000;

These should be static and final constants since you have no way to change them.

private String saltHex;
private String hashHex;

These are the only fields whose status needs to be maintained. Instead of packing all fields into the same PasswordHasher class, you should pack these two fields into a dedicated data class, use all the other code as static utilities, and let the hash method return the data class.

hash – brute force hashing of passwords with known format

The meaning of the word fortuitously It has a lot of weight in the Infosec community. In fact, some people are obsessed with it! We keep trying to get a better approximation of actual coincidence, but it can actually be impossible!

The secret to your problem is weak, not because of the reversibility of the hash (which would be very difficult), but because it is just not long enough and not fortuitously enough to have enough entropy to make a brute force attack impossible.

I see that the first "random" value is a date. It looks like the date may be relevant to the system. If the system uses sha512, this value will probably be available sometime in recent years and probably more recently!

The second "random" value is a name. I could probably get a list of names used all over the world and iterate my cracker through various combinations of them. If I could make a few guesses about a user's ethnicity, I could narrow the dictionary even further.

And you see why randomness is so important! Since these values ​​are not really random, they are much easier to guess than others, and a cracker based on dictionary attacks can be programmed to take advantage of this fact.

Hashing – An application uses a hash table with an incorrect hash function (it generates hashes that are not statistically evenly distributed). What could go wrong?

An application uses a hash table with an incorrect hash function (it generates hashes that are not statistically evenly distributed). What can result from the following?

1) Nothing. The hash table is rearranged.
2) Due to collisions, values ​​can be deleted from the table
3) Memory overload can occur
4) The search for hash table values ​​slows down …

Please answer. Thank you very much.

2D spatial hashing in C ++, which makes the game run slower

I'm trying to use spatial hashing to speed up collision detection in my game. I think spatial hashing is better for my game than quadtrees because I have a lot of fast moving objects in my game (bullets, enemies, etc.). Unfortunately, adding and removing enemies to my Spatial Hash Handler class causes the frame rate to drop to the individual digits. This also happens with relatively few (~ 10) objects on the screen, and even if I don't do collision detection.

My code is below. It is a modified version of the code from this article.

First I create the SpatialHashHandler in my CollisionHandler class and pass the screen dimensions (160 x 90 pixels) and a cell size of 10.

SpatialHashHandler s = SpatialHashHandler(160, 90, 10);

The SpatialHashHandler constructor looks like this:

SpatialHashHandler::SpatialHashHandler(float w, float h, float s){
    width = w;
    height = h;
    cellSize = s;

    cols = width  / cellSize;
    rows = height / cellSize;

    buckets.reserve(cols*rows);

    for (int i = 0; i < cols*rows; i++){
        vector bucket;
        buckets.push_back(bucket);
    }
}

Where buckets is a vector of vectors of GameObject pointers and width. height, and cellSize are swimmers and cols and rows are ints. Since my screen size is 160 x 90 pixels and cellSize 10, cols * rows corresponds to 144.

Then I start each frame by freeing the SpatialHashHandler from all enemies and reinserting them.

void CollisionHandler::insertEnemies(const vector& enemies){
    s.clearBuckets();
    for (int i = 0; i < enemies.size(); i++){
        s.insertObject(enemies(i));
    }
}


The rest of the SpatialHashHandler code is as follows:


void SpatialHashHandler::clearBuckets(){
    for (int i = 0; i < cols*rows; i++){
        buckets(i).clear();
    }
}

void SpatialHashHandler::insertObject(GameObject* object){
    vector cellIDs = getID(object);
    for (int i = 0; i < cellIDs.size(); i++){
        buckets(cellIDs(i)).push_back(object);
    }
}

vector SpatialHashHandler::getID(GameObject* object){
    vector bucketsObjectIsIn;
    bucketsObjectIsIn.reserve(2); // depending on the size of the object, it may be in multiple cells. very few objects will be in more than 2 cells at once.
    int x = object->Position()->X();
    int y = object->Position()->Y();
    int h = 1+(object->Width()  / cellSize); // rounding it upward by converting it to an int, then adding 1 or 2 is actually faster than using ceil()
    int v = 2+(object->Height() / cellSize);

    // large objects may be in multiple cells at once
    // so we start at the object's top left corner, and loop through all the cells until we get to the bottom right corner
    for (int i = 0; i < h; i++){
        for (int j = 0; j < v; j++){
            Vector2D pos = {x+i*cellSize, y+j*cellSize};
            int cell = getCell(pos);
            if (cell >= cols*rows || cell < 0){ // if the objects are off the screen, it's possible that they may be assigned to a cell that doesn't exist
                continue;
            }
            // if we get here, it means the object is on the screen
            if (std::find(bucketsObjectIsIn.begin(), bucketsObjectIsIn.end(), cell) == bucketsObjectIsIn.end()){
                // if we get here, it means the cell is not a duplicate
                bucketsObjectIsIn.push_back(cell);
            }
        }
    }
    return bucketsObjectIsIn;
}

int SpatialHashHandler::getCell(Vector2D pos){
    int x = pos.X() / cellSize;
    if (pos.X() >= width){ // if the x value is the same as the width, we'll be inserted into buckets that we aren't actually in, so we have to subtract 1
        x--;
    }
    int y = pos.Y() / cellSize;
    if (pos.Y() >= height){
        y--;
    }
    return x + y * cols;
}

void SpatialHashHandler::getCollideObjects(vector& returnObjects, GameObject* object){
    vector bucketIDs = getID(object);
    for (int i = 0; i < bucketIDs.size(); i++){
        returnObjects.insert(std::end(returnObjects), std::begin(buckets(bucketIDs(i))), std::end(buckets(bucketIDs(i))));
    }
}

Finally, in my CollisionHandler class, I loop through all of the player's balls, create a vector for each named collideEnemies, and pass both the vector and each ball to the getCollideObjects function, which returns a vector to all enemies that each ball may collide with With. I go through this vector to do actual collision detection.

void CollisionHandler::playerBulletEnemyCollisions(){

    for (int i = 0; i < BulletHandler::getTheInstance()->getPlayerBullets().size(); i++ ){

        Bullet* b = BulletHandler::getTheInstance()->getPlayerBullets()(i);
        int bx = b->Position()->X();
        int by = b->Position()->Y();
        int bw = b->Width();
        int bh = b->Height();

        vector collideEnemies;
        s.getCollideObjects(collideEnemies, b);

        for (int j = 0; j < collideEnemies.size(); j++){

            int ew = collideEnemies(j)->Width();
            int eh = collideEnemies(j)->Height();
            int ex = collideEnemies(j)->Position()->X();
            int ey = collideEnemies(j)->Position()->Y();

            // AABB() is just an ordinary bounding box collision detection method
            if (AABB(ex, ey, ew, eh, bx, by, bw, bh)){
                b->setHealth( b->Health() - 1 );
                int h = collideEnemies(j)->Health();
                collideEnemies(j)->setHealth( h - 1 );
            }
        }
    }
}

As mentioned earlier, this code causes the game's FPS to drop before any collision detection takes place (if I comment out the entire loop of collideEnemies for, the FPS will continue to drop). So I believe that it is the actual process of inserting enemies into the SpatialHashHandler (starting with the call to the CollisionHandler :: insertEnemies () function) that causes the FPS to drop.
My question is whether I am doing anything wrong or whether this code can be made more efficient so that I can use spatial hashing without lowering the game's FPS?

Blockchain – confusion about hashing and disk space

I'm having a problem understanding the concept of hashing related to disk space.

Each block is assigned to a hash. Blocks are linked together using hashes, creating a double-linked list type. We store blocks that contain the hash of the next block in the blockchain (i.e., a hard drive). This would make the hard drive full. Now we would use a different hard drive. The hash saved in the last block points to the block saved on the new hard disk. How we use the hash of the last block of the old hard drive to point to the next block stored on a brand new hard drive.

Zulfi.

hashing – where do the "magic" constants 0x9e3779b9 come from?

0x9e3779b9 is the integral part of the fraction 0.61803398875… (sqrt (5) -1) / 2 of the golden ratio multiplied by 2 ^ 32.

So if φ = (sqrt (5) +1) / 2 = 1.61803398875 is the golden ratio, the hash function calculates the fraction of n * φ that has good scattering properties. To convince yourself, just create a scatter plot of (n, n*c-FLOOR(n*c)) in your preferred table c with φ, e, π etc. Some interesting problems in real life, if it goes wrong, are described at https://lkml.org/lkml/2016/4/29/838.

This method is often referred to as "golden ratio hashing" or "Fibonacci hashing" and was popularized by Donald Knuth (The Art of Computer Programming: Volume 3: Sorting and Searching). In terms of number theory, it mainly comes down to the Steinhaus conjecture (https://en.wikipedia.org/wiki/Three-gap_theorem) and the recursive symmetry of the fractions of the multiples of the golden ratio φ.

Occasionally you can see too 0x9e3779b1, which is the closest prime number 0x9e3779b9 (and appears to be a bit of a "cargo cult" since this is not a modular hash). Similar, 0x9e3779b97f4a7c15 and 0x9e3779b97f4a7c55 are the 64-bit equivalents of these numbers.

Security – what are possible scenarios in which a state actor can harm Bitcoin if it controls more than 51% of the hashing power?

As recently reported, China controls more than 51% of hashing power and 54% only in one province in China. Suppose China has bad intentions and is forcing all of these mining operators to collude to damage the Bitcoin network. What are some of the possible scenarios to dethrone Bitcoin from the first place?

In my opinion, a 51% attack would only lead to a loss of trust, but would not kill Bitcoin because the real chain is simply self-employed.