I'm writting DApp on Ethereum (Solidity) and I need to find a solution how to store a private data on blockchain, when I also need to proceed them somehow. If it is only about storing, I can use some normal encrypting, but the problem is that I need to read the data IN the smart contract and proceed it somehow too.
Let's say:
1) I want to send some private number to a blockchain.
2) I need to check if the privete number is bigger than the last stored private number and smaller than the second last stored number.
if (storage[n] < y < storage[n-1]) storage.push(y);
3) If yes, I want to store it privately.
Any ideas? Thank you.
it is better to use a data structure with two entries e.g. a tuple, with the first entry to use as the counter (i.e. to take care of check if the private number is bigger than the last stored private number part, and the second entry to store an encrypted data, one to use as a counter.
y = new Dapp(sno, value)
# compare y's sno with the record, store private data in value
You can encrypt the data before sending to the blockchain. Encryption and decryption should be done off-chain because the blockchain is public and you don't want your plaintext to be exposed.
You can compare those numbers on-chain without exposing your plaintext if you use homomorphic encryption.
Homomorphic encryption is a form of encryption that allows computation on ciphertexts, generating an encrypted result which, when decrypted, matches the result of the operations as if they had been performed on the plaintext. - Wikipedia
Related
Since chaincode has to be deterministic, is there any way to get same random number in all endorser nodes to implement something like a lottery? In Ethereum you can do something like that:
function random() private view returns (uint) {
return uint(keccak256(abi.encodePacked(block.difficulty, now, players)));
}
By using the blocknumber, timestampt, block difficulty, gas , etc...But you dont have that in Hyperledger Fabric.
You're quite correct that the deterministic nature of chaincode does cause issues with random numbers.
I'd look into doing this in one of two ways.
You need to pass in the random number (or at least a seed) as part of the transaction request. You might want to send this in transient data so that's not recorded on the ledger.
Pre-store the random numbers. i.e. generate a massive table of random numbers and put those into the ledger in some form of setup transaction. Maybe even into the private data collections. Work along those each time you need a number using a counter.
You can protect access to the set of generated numbers by various type of access control.
We can use the timestamp passed by proposer of transaction as the seed.
Usage: stub.GetTxTimestamp()
// GetTxTimestamp returns the timestamp when the transaction was created. This
// is taken from the transaction ChannelHeader, therefore it will indicate the
// client's timestamp and will have the same value across all endorsers.
GetTxTimestamp() (*timestamp.Timestamp, error)
I read
https://hyperledger-fabric.readthedocs.io/en/release-2.0/private-data/private-data.html says that
"A hash of that data, which is endorsed, ordered, and written to the ledgers of every peer on the channel. The hash serves as evidence of the transaction and is used for state validation and can be used for audit purposes." .
However, I think signatures of the transaction is enough for evidence that contract was agreed upon.
Why hash of the data should be shared among the every peers?
Private transactions are not stored in blocks in the chain like public transactions. All the peers joined to the channel share the same channel chain. Thus, if the private transaction were stored normally in the chain, every peer (even those from organizations to which the transaction is not destined) could read the private transaction parameters (and reconstruct the others' private state). To avoid this, basically, a hash is stored in the block in its place so that the organizations which share the private data can still check integrity.
EDIT:
Let's see, if you read carefully https://hyperledger-fabric.readthedocs.io/en/release-2.0/private-data/private-data.html#transaction-flow-with-private-data, you'll see that at no time is the private data signed (neither the readset, nor the writeset, nor the input, nor the output). In step 3 a signature is produced only over its hash (embedded in the transaction). Nothing else. The private data (the data, not the transaction) is simply distributed via gossip protocol and stored temporally in the transient data store (point 2), to be committed in point 5. The only evidence on the private data is the hash (which is embedded in the transaction and signed). The gossip protocol has its security mechanisms, but it does not produce evidence or guarantee the transaction order.
Now, take the case where, later, a malicious organization unilaterally alters its private state in order to obtain some kind of benefit. That hash in the chain would be the only evidence left to resolve the dispute with other organizations. There is no other evidence on the agreed valid value (and the execution order) than that hash. No plain text private data was signed by the peer.
That's the way it is at Fabric. And it makes sense. Keep in mind that it is necessary to guarantee the integrity of the data and the order in which the transactions are executed, so at some point the orderer (point 4) has to be involved to determine the order (in most cases the order of the transactions does alter the product) without disclosing the real data.
What I feel is that, when only signature is shared, how does other peers validate what the signature is for? Or vice versa, how to validate whether it is actually being signed by the claimed owner? So, we share hash of the transaction + signature of that hash. This signature now can be verified using public certificate of that owner. Also, as the transaction is hashed, it remains private but the ledger (blocks chained to one another) is identical among all peers.
I am using Redis key-value pair for storing the data. The data against a particular key can change at any point of time, so after every retrieval request I asynchronously update the data stored against the requested key so that the next request can be served with updated data.
I have done quite a bit of testing but still I am wondering if there could be any case where this approach might have some negative consequences?
PS: The data is consolidated from multiple servers.
Thanks in advance for any help/suggestions.
If you already know the value to be stored, you can use GETSET (or a transaction if it is not a simple string type).
If the new value is some manipulation on the value i.e. f(value), you should do it in a LUA script.
Otherwise some other client might read the old value before you update it.
I wanted to know what was the best practice followed for storing sensitive fields like email and phone number in the database. Lets say you want to search by email and phone number , and the application sends emails and sms to its users as well.
Because this data is sensitive you need to encrypt it. Hashing is not an option because you cant unhash it.
Encryption standards like Rjindael or AES makes the data secure, but you cannot search the db by it because the encrypted string produced for the same input is always different.
So in a case like this do I need to store both the hash as well as the encrypted field in the table ? Or is there some other strong encryption technique deployed for fields like these.
Check out CipherSweet. It's a very permissively-licensed open source library that provides searchable encryption in PHP.
Its implementation is similar to Ebbe's answer, but with a lot more caveats:
CipherSweet automatically handles key splitting, through a well-defined protocol.
CipherSweet supports multiple functional blind indexes (truncated hashes of transformations of the plaintext) to facilitate advanced searching.
More about the security implications of its design are available here.
Furthermore, the API is relatively straightforward:
<?php
use ParagonIE\CipherSweet\BlindIndex;
use ParagonIE\CipherSweet\CipherSweet;
use ParagonIE\CipherSweet\CompoundIndex;
use ParagonIE\CipherSweet\EncryptedRow;
use ParagonIE\CipherSweet\Transformation\LastFourDigits;
/** #var CipherSweet $engine */
// Define two fields (one text, one boolean) that will be encrypted
$encryptedRow = (new EncryptedRow($engine, 'contacts'))
->addTextField('ssn')
->addBooleanField('hivstatus');
// Add a normal Blind Index on one field:
$encryptedRow->addBlindIndex(
'ssn',
new BlindIndex(
'contact_ssn_last_four',
[new LastFourDigits()],
32 // 32 bits = 4 bytes
)
);
// Create/add a compound blind index on multiple fields:
$encryptedRow->addCompoundIndex(
(
new CompoundIndex(
'contact_ssnlast4_hivstatus',
['ssn', 'hivstatus'],
32, // 32 bits = 4 bytes
true // fast hash
)
)->addTransform('ssn', new LastFourDigits())
);
Once you have your object instantiated and configured, you can insert rows like so:
<?php
/* continuing from previous snippet... */
list($encrypted, $indexes) = $encryptedRow->prepareRowForStorage([
'extraneous' => true,
'ssn' => '123-45-6789',
'hivstatus' => false
]);
$encrypted['contact_ssnlast4_hivstatus'] = $indexes['contact_ssnlast4_hivstatus'];
$dbh->insert('contacts', $encrypted);
Then retrieving rows from the database is as simple as using the blind index in a SELECT query:
<?php
/* continuing from previous snippet... */
$lookup = $encryptedRow->getBlindIndex(
'contact_ssnlast4_hivstatus',
['ssn' => '123-45-6789', 'hivstatus' => true]
);
$results = $dbh->search('contacts', ['contact_ssnlast4_hivstatus' => $lookup]);
foreach ($results as $result) {
$decrypted = $encryptedRow->decrypt($result);
}
CipherSweet is currently implemented in PHP and Node.js, with additional Java, C#, Rust, and Python implementations coming soon.
Actually, encrypting the same message twice with AES with the same key and the same initialization vector (IV) will produce the same output - always.
However, using the same key and the same IV would leak information about the encrypted data. Due to the way AES encrypts in blocks of 16 bytes, two email addresses starting with the same 16 bytes and encrypted with the same key and the same IV would also have the same 16 bytes in the start of the encrypted message. Those leaking the information that these two emails start with the same. One of the purposes of the IV is to counter this.
A secure search field can be created using an encrypted (with same key and same IV) one-way-hash. The one-way-hash ensures that the encryption don't leak data. Only using a one-way-hash would not be enough for e.g telephone numbers as you can easily brute force all one-way-hash'es for any valid phone numbers.
If you want to encrypt your data, place the table on an encrypted filesystem or use a database that provides a facility for encrypted tables.
Encrypting data in the database itself would lead to very poor performance for a number of reasons, the most obvious being that a simple table scan (let's say you're looking for a user by email address) would require a decryption of the whole recordset.
Also, your application shouldn't deal with encryption/decryption of data: if it is compromised, then all of your data is too.
Moreover, this question probably shouldn't be tagged as 'PHP' question.
I want to create a unique id for a device, so I have decided to create SHA1(mac XOR timestamp XOR user_password). Is there any security problem related with this? Would it be better to do SHA1(mac CONCATENATE timestamp CONCATENATE user_password)?
Thank you
Use concatenation - then you'll be basing your hash on all of the available source data.
If you use XOR then there's a risk that one piece of your source data will "cancel out" some (or all) of the bits of the remaining data before it's even passed to the hash function.
And concatenating rather than XORing won't affect the space required for storage of your hash - the generated SHA1 hash will always be 20 bytes regardless of the size of your source data.