How to store public/private key securely - security

Looking to store public/private key information securely on an iOS device. I know I want to store this in the KeyChain however I am not 100% sure what sort of attributes I need to populate in the SecRecord. I was going to do something like:
// private key
SecKeyChain.Add(new SecRecord(SecKind.Key)
{
Accessible = SecAccessible.AlwaysThisDeviceOnly,
KeySizeInBits = 512,
KeyClass = SecKeyClass.Private,
CanSign = true,
ValueData = privateKeyValue,
Account = publicKeyValue
});
Which would store the private key, then follow a similar approach for the public key replacing the Account attribute with a value unique to the user e.g. username. However, not sure if this is the right way to use this.
Does anyone have a good examples on how you would do this specifically for keys?

Decided to go with the following approach:
// store public key
SecKeyChain.Add(new SecRecord(SecKind.Key)
{
ApplicationLabel = userName,
Accessible = SecAccessible.AlwaysThisDeviceOnly,
KeySizeInBits = 512,
KeyClass = SecKeyClass.Public,
ValueData = NSData.FromString(publicKey)
});
// store private key
SecKeyChain.Add(new SecRecord(SecKind.Key)
{
ApplicationLabel = publicKey,
Accessible = SecAccessible.AlwaysThisDeviceOnly,
KeySizeInBits = 512,
KeyClass = SecKeyClass.Private,
CanSign = true,
ValueData = NSData.FromString(secretKey)
});
This means each public key is mapped to an individual user and each private key is mapped to a public key which allows me to store multiple user keys (rather than only storing current logged in users).
Seems to work ok, however, still not 100% sure it is the correct way to do this kind of thing so some clarification would be nice.

Related

Fetching OpenIdConnectConfiguration while offline/no connection to AuthServer

I've been working on how to save OpenIdConnecConfiguration locally in the odd case that the AuthServer is not reachable but the frontend client (e.g. Phone) still has a valid refresh token which still needs to be validated again when signing in. It is also needed to be saved locally to a file in the case that the backend (e.g. WCF) has restarted due to a update or the frequent restarts it has (once a day)
What I've done so far, I've saved the JSON object of the ".well-known/openid-configuration" to a file/variable and now I want to create the OpenIdConnectConfiguration object.
OpenIdConnectConfiguration.Create(json) does a lot of the work but the signingKeys do not get created. I think maybe it's because the authorization endpoint needs to be created in some other manner maybe?
Or maybe I'm doing this the wrong way and there is another solution to this issue. I'm working in C#.
Edit: I know there are some caveats to what I'm doing. I need to check once in awhile to see if the public key has been changed, but security wise it should be fine to save the configuration because it's already public. I only need the public key to validate/sign the jwt I get from the user and nothing more.
Figured out a solution after looking through OpenIdConnectConfiguration.cs on the official github.
When fetching the OpenIdConnectConfiguration the first time, use Write() to get a JSON string and use it to save it to file.
Afterwards when loading the file, use Create() to create the OpenIdConnectConfiguration again from the JSON string (This had the issue of not saving the signingKeys as said in the question, but alas! there is a fix)
Lastly to fix the issue with the signingKeys not being created, (this is what I found out from the github class) all we need to do is loop through the JsonWebKeySet and create them as is done in the class. We already have all the information needed from the initial load and therefore only need to create them again.
I'll leave the code example below of what I did. I still need to handle checking if he key has been changed/expired which is the next step I'll be tackling.
interface IValidationPersistence
{
void SaveOpenIdConnectConfiguration(OpenIdConnectConfiguration openIdConfig);
OpenIdConnectConfiguration LoadOpenIdConnectionConfiguration();
}
class ValidationPersistence : IValidationPersistence
{
private readonly string _windowsTempPath = Path.GetTempPath();
private readonly string _fileName = "TestFileName";
private readonly string _fullFilePath;
public ValidationPersistence()
{
_fullFilePath = _windowsTempPath + _fileName;
}
public OpenIdConnectConfiguration LoadOpenIdConnectionConfiguration()
{
FileService fileService = new FileService();
OpenIdConnectConfiguration openIdConfig = OpenIdConnectConfiguration.Create(fileService.LoadFromJSONFile<string>(_fullFilePath));
foreach (SecurityKey key in openIdConfig.JsonWebKeySet.GetSigningKeys())
{
openIdConfig.SigningKeys.Add(key);
}
return openIdConfig;
}
public void SaveOpenIdConnectConfiguration(OpenIdConnectConfiguration openIdConfig)
{
FileService fileService = new FileService();
fileService.WriteToJSONFile(OpenIdConnectConfiguration.Write(openIdConfig), _fullFilePath);
}
}

How to call a contract function from a specific address

I want to use web3 to call a contract function(sendTransaction not call) from a specific address that I hold the private key to. I also have the contract instance connected. I know I have to dio something like web3.personal.unlockAccount(address,password,duration)
And then specify the from address.
So my question is, is "password" where I enter my private key? And how do I pass that address into fromAddress once I unlock it.
Or is there a more streamlined way to go about it?
is "password" where I enter my private key?
No, it's not. Actually it is a password, which you entered when you were creating account and which was used to generate your keystore file.
If you use web3.personal.unlockAccount(address,password,duration) you need to have your keystore file in the keystore folder near chaindata of geth.
Another way will be to use web3.eth.sendRawTransaction from web3.py, but it will be a little bit clunky to call contract method from it.
key = '0x' + 'YOUR-PRIVATE-KEY
transaction = {
'to': _to,
'value': 0,
'gas': 300000,
'gasPrice': 23000000000,
'nonce': web3.eth.getTransactionCount(_from),
'chainId': int(web3.admin.nodeInfo['protocols']['eth']['network']),
'data': b''
}
signed = web3.eth.account.signTransaction(transaction, key)
print("Transaction Hash: " + web3.toHex(web3.eth.sendRawTransaction(signed.rawTransaction)))
My suggestion will be to create keyfile recognisable by Ethereum clients by using web3.eth.account.encrypt (web3.py because web3.js yet lack this functionality) and after you generate it put it in the right folder and try simply to unlock account.

Get old data in preUpdate Sonata Admin Bundle

I have a product entity and it has an images field that store the images names from the product but the images names depends of a part_number field that is unique, so if the user make a mistake in the part number and he wants to edit it then I also have to change the images names
I tried this but it does not works:
// class ProductsAdmin extends Admin
public function preUpdate($product) {
$old_product = $this->getSubject();
if ($old_product->getPartNumber() != $product->getPartNumber)
{
// change file names
}
$this->saveFile($product);
}
How I get the original row in preUpdate() function?
According to the topic taken from the official SonataAdmin google forum:
https://groups.google.com/forum/#!topic/sonata-devs/0zML6N13i3U
you need to make use of the class UnitOfWork:
http://www.doctrine-project.org/api/orm/2.3/class-Doctrine.ORM.UnitOfWork.html
Do this way:
public function preUpdate($object)
{
$em = $this->getModelManager()->getEntityManager($this->getClass());
$original = $em->getUnitOfWork()->getOriginalDocumentData($object);
}
Thus you get an array of values of your database entity.
E.g: to get access to the value password of your entity do:
$password = $original['password'];
That's all.
Enjoy :)
If you just do a doctrine query in the preUpdate function to get the product from the database you'll have the old object. Then do the comparison and you're good to go.

Persistent Store save boolean as objects

I am developing a BlackBerry App and saving a lot of values as String and boolean to the Persistent Store. I am aware of the fact that String and boolean values do not get deleted from Persistent when an App is deleted/uninstalled from the handset. I am also aware of the fact that in order to delete these values I need to store this in a "project" specific class. I have been struggling with it and so would want a temporary work around. I am saving a boolean value in order to determine which screen the App should load it.
PersistentStoreHelper.persistentHashtable.put("flagged",Boolean.TRUE);
if (PersistentStoreHelper.persistentHashtable.containsKey("flagged"))
{
boolean booleanVal = ((Boolean) PersistentStoreHelper.persistentHashtable.get("flagged")).booleanValue();
if (booleanVal==true)
{
pushScreen(new MyScreen());
}
}
else
{
pushScreen(new MyScreen(false));
}
Is it possible to store this boolean value as an Object so that it gets deleted when the App is uninstalled/deleted. Please help as well as comment if I am missing out on anything.
Once again, I'd recommend you change your PersistentStoreHelper to this version online.
You certainly can get Boolean and String values to be deleted from the persistent store when your app is uninstalled, but they need to be inside an object that can only exist in your app.
For example:
PersistentStoreHelper store = PersistentStoreHelper.getInstance();
store.put("flagged", Boolean.TRUE);
// commit will save changes to the `flagged` variable
store.commit();
and then retrieve it later with:
PersistentStoreHelper store = PersistentStoreHelper.getInstance();
boolean isFlagged = ((Boolean)store.get("flagged")).booleanValue();
The key that makes this work is inside my PersistentStoreHelper class, it saves everything inside a subclass of Hashtable that's unique to my/your app (MyAppsHashtable). You need to store your String or Boolean objects inside that app-unique Hashtable subclass, not in a normal java.util.Hashtable.
Again, please make this easy on yourself, and use the code I posted.
Note: also, you probably know this, but you may need to reboot your device to see the app, and its persistent store data, fully deleted.
Update
If you had changed the original PersistentStoreHelper class that I had posted online, because you wanted access to the containsKey() method, or other methods in the Hashtable class, you can solve that problem by simply adding code like this:
public boolean containsKey(String key) {
return persistentHashtable.containsKey(key);
}
to the PeristentStoreHelper class. Please don't make persistentHashtable a public static member. As you need to use more Hashtable methods, just add wrappers for them, like I show above with containsKey(). Of course, you can achieve the same thing as containsKey() by simply using this code:
boolean containsFlagged = (store.get("flagged") != null);
Update 2
If you get stuck with old persistent data, that you need to clean out, you can modify PersistentStoreHelper to detect and correct the situation, like this (hattip to #adwiv for suggestions):
private PersistentStoreHelper() {
persistentObject = PersistentStore.getPersistentObject(KEY);
Object contents = persistentObject.getContents();
if (contents instanceof MyAppsHashtable) {
persistentHashtable = (MyAppsHashtable)contents;
} else {
// store might be empty, or contents could be the wrong type
persistentHashtable = new MyAppsHashtable();
persistentObject.setContents(persistentHashtable);
persistentObject.commit();
}
}

Noob way to login the user in Prestashop

This is a walkthrough on how to make a user login on prestashop without passing through the login screen. This is helpful if you do not want the user to login again like when you want to transfer his session from one website to prestashop.
Step 1 Eliminate the need for password salting. Under config/settings.inc.php, set _COOKIE_KEY_ to blank. Note this also means that you must create a new customer. Or you can delete the old md5 password from DB and add your own.
Step 2 In the authentication.php file paste the following lines after line 6:
$customer = new Customer();
//$authentication = $customer->getByEmail(trim($email), trim($passwd));
$authentication = $customer->getByMd5(trim($email), trim($passwd)); //modified version of getByEmail if we are not accepting $passwd in cleartext but in md5.
/* Handle brute force attacks */
sleep(1);
if (!$authentication OR !$customer->id)
$errors[] = Tools::displayError('authentication failed');
else
{
$cookie->id_customer = intval($customer->id);
$cookie->customer_lastname = $customer->lastname;
$cookie->customer_firstname = $customer->firstname;
$cookie->logged = 1;
$cookie->passwd = $customer->passwd;
$cookie->email = $customer->email;
if (Configuration::get('PS_CART_FOLLOWING') AND (empty($cookie->id_cart) OR Cart::getNbProducts($cookie->id_cart) == 0))
$cookie->id_cart = intval(Cart::lastNoneOrderedCart(intval($customer->id)));
Module::hookExec('authentication');
if ($back = Tools::getValue('back'))
Tools::redirect($back);
//Tools::redirect('my-account.php'); //cut redirection to break infinite loop
}
The above code is what makes the user login using $email as username and $passwd as password in plaintext. The original code comes from the if (Tools::isSubmit('SubmitLogin')) function inside the authentication.php file.
Step 3 Paste the above code in the products.php file just under line 5
Step 4 In case you are sending $passwd directly in md5 format, here is the modified version of getByEmail()(customer.php):
public function getByMd5($email, $passwd = NULL)
{
$result = Db::getInstance()->GetRow('SELECT * FROM `'._DB_PREFIX_ .'customer` WHERE `active` = 1 AND `email` = \''.pSQL($email).'\' '.(isset($passwd) ? 'AND `passwd` = \''.pSQL(_COOKIE_KEY_.$passwd).'\'' : '').' AND `deleted` = 0');
if (!$result)
return false;
$this->id = $result['id_customer'];
foreach ($result AS $key => $value)
if (key_exists($key, $this))
$this->{$key} = $value;
return $this;
}
You can get access to the username/passwd either through the $_COOKIE[] function or through $_GET[]. Either way its a big security risk. Cookie reading can be placed in the index.php file.
This approach you have proposed is extremely insecure. A salt is required for password safety and should never be removed. Further more by authenticating a user with their MD5 hash you effectively voiding all protection that hashing passwords provides you. People hash passwords because attacks like SQL injection allow an attacker to obtain this hash which then needs to be cracked. In this scenario the attacker can grab the admin's hash and just login right away.
The correct way to do session sharing:
Create a simple table to store session state. In this case the Cryptgoraphic Nonce is a large random value used to reference the data.
'insert into session_state (sess,token) value ('.pSQL(serialize($_SESSION)).', '.$cryptographic_nonce.')'
When the browser is redirected to another shop give them a redirect like this:
header('location: https://some_other_shop/landing.php?token=$cryptographic_nonce');
When the new server gets this landing request it fetches the session state from the previous server:
$sess=http_get($_SERVER['HTTP_REFERER']."?token=$_GET[token]");
$_SESSION=unserialize($sess);
Note you might have to transfer the user's data in the database as well.

Resources