I am trying to create a Desktop app (java) that points to the same database of my website (created using symfony 2), but I have the problem that I canot insert in the columns "password" and "salt" using the same encryption type sha512 generated by fosuserBundle, and I do not know how fosuserBundle generates the "salt" value.
My encoder is currently set as:
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
Check FOS\UserBundle\Model\User __construct method:
public function __construct()
{
$this->salt = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
$this->enabled = false;
$this->locked = false;
$this->expired = false;
$this->roles = array();
$this->credentialsExpired = false;
}
finally i find solution that make the field "salt" negligible in table fos_user is to make this methode just return the password
namespace Symfony\Component\Security\Core\Encoder;
protected function mergePasswordAndSalt($password, $salt)
{
if (empty($salt)) {
return $password;
}
if (false !== strrpos($salt, '{') || false !== strrpos($salt, '}')) {
throw new \InvalidArgumentException('Cannot use { or } in salt.');
}
return $password;
}
Related
I am a iOS developer and trying to use Secure enclave to generate ECC pair key. I am able to do that successfully using the sample app here: https://github.com/agens-no/EllipticCurveKeyPair. When I use this key along with a Python implementation to do encryption and decryption mentioned here: https://gist.github.com/dschuetz/2ff54d738041fc888613f925a7708a06 it works.
The problem is that i need a Java code to do the same. Can anyone help me to achieve this or point me to a code that does the same job of as Python code is doing.
On iOS side I am doing eciesEncryptionStandardX963SHA256AESGCM encrypt and decrypt logic.
I know i should have tried to solve this myself. But I am a iOS Engineer and trying my hands on Java backend. Would be really helpful if someone can guide me.
Created a sample Java code based on the answer. Link to code: https://gist.github.com/balrajOla/fa2f6030538b20a396c086377a6f7114
Using the sample iOS App provided here: https://github.com/agens-no/EllipticCurveKeyPair. I generated ECC keys.
Then pass the public key to the Java code to create an encrypted message. This encrypted messages is passed back to sample iOS app mentioned above to be decrypted using eciesEncryptionStandardX963SHA256AESGCM algo.
But we get an error mentioned below snapshot.
We had the same problem. We want to bring a EC key exchange working from iOS secure enclave with a Java Back-end.
After three days of trial&error, we finally found a Java implementation which is working.
Java code was taken from https://github.com/O2-Czech-Republic/BC-ECIES-for-iOS
And the iOS code, using eciesEncryptionCofactorVariableIVX963SHA256AESGCM algorithm:
static func getExportableKeyFromECKey() -> String? {
// If exists already a created EC Key, then export the public part
if let privateKey = self.loadECPrivateKey() {
if let publicKey = self.getECPublicKey(privateKey) {
if self.algorithmAcceptedForEC(publicKey) {
var error: Unmanaged<CFError>?
// Get Public key External represenatation
guard let cfdata = SecKeyCopyExternalRepresentation(publicKey, &error) else {
return nil
}
let pubKeyData: Data = cfdata as Data
return pubKeyData.base64EncodedString()
}
}
}
// If no EC Key created, then first create one
else {
var error: Unmanaged<CFError>?
let tag = Config.skName.data(using: .utf8) ?? Data()
let attributes: [String: Any] = [kSecClass as String: kSecClassKey,
kSecAttrKeyType as String: Config.skType,
kSecAttrKeySizeInBits as String: Config.ecKeySize,
kSecPrivateKeyAttrs as String: [ kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: tag]]
do {
// Create Private Key
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
throw error!.takeRetainedValue() as Error
}
// Get Public Key
guard let publicKey = SecKeyCopyPublicKey(privateKey) else {
throw error!.takeRetainedValue() as Error
}
// Get Public key External represenatation
guard let cfdata = SecKeyCopyExternalRepresentation(publicKey, &error) else {
throw error!.takeRetainedValue() as Error
}
let pubKeyData: Data = cfdata as Data
return pubKeyData.base64EncodedString()
} catch {
print(error)
}
}
return nil
}
static func loadECPrivateKey() -> SecKey? {
let tag = Config.skName.data(using: .utf8)!
let query: [String: Any] = [kSecClass as String: kSecClassKey,
kSecAttrApplicationTag as String: tag,
kSecAttrKeyType as String: Config.skType,
kSecReturnRef as String: true]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
guard status == errSecSuccess else {
return nil
}
print("LOAD PRIVATE KEY: \n \(item as! SecKey) \n")
return (item as! SecKey)
}
static func getECPublicKey(_ privateKey: SecKey) -> SecKey? {
guard let publicKey = SecKeyCopyPublicKey(privateKey) else {
// Can't get public key
return nil
}
return publicKey
}
static func algorithmAcceptedForEC(_ publicKey: SecKey) -> Bool {
guard SecKeyIsAlgorithmSupported(publicKey, .encrypt, Config.ecAlgorithm) else {
// Algorith not supported
print("\nEncrytion Algorithm not supported!!!\n")
return false
}
return true
}
/// if let encryptedData = Data(base64Encoded: "BOqw779hxsGLMEV7X81Mphcx+SMtxSQs388s5CydkvJ4V2XuuWoyp48GCmgDMBnYlEIRqAdHxIc/Ts3ATxa9ENCDGdIZf5CjpWsOIVXYxLvupdap4w==", options:.ignoreUnknownCharacters)
static func decryptStr(_ encData: Data) {
/// 1. Step: Get the Private Key and decrypt the symmetric key
let privateKey = loadECPrivateKey()
guard SecKeyIsAlgorithmSupported(privateKey!, .decrypt, Config.ecAlgorithm) else {
print("Can't decrypt\nAlgorithm not supported")
return
}
DispatchQueue.global().async {
var error: Unmanaged<CFError>?
let clearTextData = SecKeyCreateDecryptedData(privateKey!,
Config.ecAlgorithm,
encData as CFData,
&error) as Data?
DispatchQueue.main.async {
guard clearTextData != nil else {
print("Can't decrypt")
return
}
let clearText = String(decoding: clearTextData!, as: UTF8.self)
print("Decrypted Info: \(clearText)")
// clearText is our decrypted string
}
}
}
In Java you have two interesting classes - ECGenParameterSpec and KeyPairGenerator. ECGenParameterSpec specifies parameters for generating elliptic curve domain parameters, and KeyPairGenerator is used to generate pairs of public and private keys.
In the book Android Security Internals by Nokilay Elenkov there's a good code example of their combination to generate the key pair.
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDH");
ECGenParameterSpec ecParamSpec = new ECGenParameterSpec("secp256r1");
kpg.initialize(ecParamSpec);
KeyPair keyPair = kpg.generateKeyPair();
This is the explanation given about the previous code
There are two ways to initialize a KeyPairGenerator: by specifying the
desired key size and by specifying algorithm-specific parameters. In
both cases, you can optionally pass a SecureRandom instance to be used
for key generation. If only a key size is specified, key generation
will use default parameters (if any). To specify additional
parameters, you must instantiate and configure an
AlgorithmParameterSpec instance appropriate for the asymmetric
algorithm you are using and pass it to the initialize() method, as
shown in Example 5-15. In this example, the ECGenParameterSpec
initialized in line 2 is an AlgorithmParameterSpec that allows you to
specify the curve name used when generating Elliptic Curve (EC)
cryptography keys. After it is passed to the initialize() method in line 3,
the subsequent generateKeyPair() call in line 4 will use the specified
curve (secp256r1) to generate the key pair.
I have an object store I need to export or download as a .csv file. I have done some searching and I can't seem to find information on this function. Responses that do not utilize IDB are welcome.
Some background: This is part of a project for work, and I dove into this project without prior knowledge of coding whatsoever. I am using a company issued chromebook, so (as far as I know) NPM installs are not available.
App Background: The project is a customer survey operated through a single terminal. That terminal being my chromebook with hopes to move to an ipad if I can successfully download user inputs to .csv file.
What I have so far:
(function leadIDB() {
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB|| window.msIndexedDB;
if (!window.indexedDB) {
alert('indexDB not supported in this browser');
}
let request = window.indexedDB.open("leadDB", 1),
db,
tx,
store,
index;
request.onupgradeneeded = function(e) {
let db = request.result,
store = db.createObjectStore("LeadStore", {keyPath: "leadID", autoIncrement: true});
index = store.createIndex("firstName", "firstName", {unique: false});
};
request.onerror = function(e) {
console.log("There was an error: " + e.target.errorCode);
};
request.onsuccess = function(e) {
db = request.result;
tx = db.transaction("LeadStore", "readwrite");
store = tx.objectStore("LeadStore");
index = store.index("firstName");
db.onerror = function(e) {
console.log("ERROR" + e.target.errorCode);
};
store.put(newLead);
let lead = store.getAll();
lead.onsuccess = function() {
console.log(lead.result);
console.log(lead.result.firstName);
};
tx.oncomplete = function() {
console.log('Item added to LeadDB');
db.close();
};
};
})();
You are on the right track. There are a few more things to do. First, you need to be able to continue processing once you have loaded the data from indexedDB into js memory. Next, you need to generate the CSV file in memory (as a gigantic string). Next, you need to convert the csv string into a File (which implements Blob). Finally, you want to trigger the download of the file.
There are a few ways to do the first step. I am going to use a promise, but you could do this with a callback or whatever you fancy.
function loadData() {
return new Promise((resolve, reject) => {
var openrequest = indexedDB.open(...);
openrequest.onupgradeneeded = ...;
openrequest.onerror = event => reject(event.target.error);
openrequest.onsuccess = event => {
var db = event.target.result;
var txn = db.transaction(...);
var store = txn.objectStore(...);
var loadrequest = store.getAll();
loadrequest.onerror = event => reject(event.target.error);
loadrequest.onsuccess = event => {
var data = event.target.result;
resolve(data);
};
};
});
}
// You could call the function like this for example:
async function foo() {
var data = await loadData();
console.log('loaded the data, loaded %d objects', data.length);
}
Next, you want to convert the data into a csv-formatted string.
// This is not perfect, just an example of getting you closer
function toCSV(data) {
var output = [];
for(var object of data) {
var row = [];
for(var prop in object) {
row.push(to_csv_value(object[prop]));
row.push(',');
}
row.push('\n');
output.push(row.join(''));
}
return output.join('');
}
function to_csv_value(value) {
var output = '"';
output += value.replace('"', '\\"');
return output + '"';
}
// and then to compose it for example:
async function foo() {
var data = await loadData();
var csvstring = toCSV(data);
}
Next, you want to create a file. You can use the Blob constructor to do this. Something like the following:
// Because File implements blob interface, we are effectively creating a file
// by creating a blob
function createCSVFileFromString(string) {
var csv_mime_type = 'text/csv';
return new Blob([string], {type: csv_mime_type});
}
// And again, to compose it:
async function foo() {
var data = await loadData();
var string = toCSV(data);
var blob = createCSVFileFromString(string);
}
The next step is to make the blob downloadable. This can typically be done using the object url strategy. Kind of like the following:
function downloadBlob(blob, filename) {
var anchor = document.createElement('a');
anchor.setAttribute('download', filename);
var url = URL.createObjectURL(blob);
anchor.setAttribute('href', url);
anchor.click();
URL.revokeObjectURL(url);
}
// And finally, to compose it all together
async function loadAndStartDownloadingData() {
var data = await loadData();
var csvstring = toCSV(data);
var blob = createCSVFileFromString(csvstring);
downloadBlob(blob, 'mydata.csv');
}
Then, somewhere in your application, let's say on click of button, you would do something like this. Im using non-async syntax here just for example of using promise in non-await, you want to always be careful to not hide errors.
var button = ...;
button.onclick = function(event) {
// Load the data and trigger the download, and send any problems to console
loadAndStartDownloadingData().catch(console.warn);
};
Note, this doesn't cover inserting the data, but I'm sure you can figure that out.
I have written a Java application that searches Active directory via LDAP for user information. I have a list of instances of custom Person class that is passed in. In it I have either DN or email defined. I am modifying the search criteria accordingly. Here is the code:
for (Person person : members) {
boolean ready = false;
String filter = getConfig().getUserSearchFilter();
// (&(|(objectclass=user)(objectclass=person)(objectclass=inetOrgPerson)(objectclass=organizationalPerson)))
String base = person.getDistinguishedName();
if (base != null && !base.isEmpty()) {
ready = true;
} else if (person.getEmail() != null) {
base = getConfig().getMemberSearchBase();
// ou=Users,ou=Managed,dc=division,dc=company,dc=com
String mail = person.getEmail();
StringBuilder filterBuilder = new StringBuilder(filter);
int pIdx = filterBuilder.lastIndexOf(")");
filterBuilder.insert(pIdx, "(|(mail=" + mail + ")(x-personalmail=" + mail + "))");
filter = filterBuilder.toString();
LOG.debug("New value of a filter = {}", filter);
ready = true;
}
if (ready) {
try {
NamingEnumeration<SearchResult> search = getContext().search(base, filter, searchControls);
...
} catch (NamingException nex) {
throw new IOException(nex);
}
} else {
LOG.error("Incorrect search criteria for user {} of group {}. Person skipped", person.getName(), this.group.getName());
}
}
Code is working without errors, but when DN is specified it does find a person, but when email is defined it finds nothing.
However, If I copy generated filter string and pass it to ldapsearch command in a form of:
ldapsearch -LLL -x -H ldaps://my.ldap.server.com -D 'svc-acct#corp-dev.company.com' -W -b "ou=Users,ou=Managed,dc=division,dc=company,dc=com" '(&(|(objectclass=user)(objectclass=person)(objectclass=inetOrgPerson)(objectclass=organizationalPerson))(|(mail=person#domain.com)(x-personalmail=person#domain.com)))'
It does find this person perfectly.
Did anyone faced similar problem? Do you see any flaws in my code?
Please, do help me.
I did find the cause of my problem.
In the search control I had scope defined as OBJECT_SCOPE.
It does work when you are specifying DN, but with the search per one of the fields it fails finding the object.
I changed the scope to SUBTREE_SCOPE and everything started working as expected.
According to the official documentation Update API - Upserts one can use scripted_upsert in order to handle update (for existing document) or insert (for new document) form within the script. The thing is they never show how the script should look to do that. The Java - Update API Doesn't have any information on the ScriptUpsert uses.
This is the code I'm using:
//My function to build and use the upsert
public void scriptedUpsert(String key, String parent, String scriptSource, Map<String, ? extends Object> parameters) {
Script script = new Script(scriptSource, ScriptType.INLINE, null, parameters);
UpdateRequest request = new UpdateRequest(index, type, key);
request.scriptedUpsert(true);
request.script(script);
if (parent != null) {
request.parent(parent);
}
this.bulkProcessor.add(request);
}
//A test call to validate the function
String scriptSource = "if (!ctx._source.hasProperty(\"numbers\")) {ctx._source.numbers=[]}";
Map<String, List<Integer>> parameters = new HashMap<>();
List<Integer> numbers = new LinkedList<>();
numbers.add(100);
parameters.put("numbers", numbers);
bulk.scriptedUpsert("testUser", null, scriptSource, parameters);
And I'm getting the following exception when "testUser" documents doesn't exists:
DocumentMissingException[[user][testUser]: document missing
How can I make the scriptUpsert work from the Java code?
This is how a scripted_upsert command should look like (and its script):
POST /sessions/session/1/_update
{
"scripted_upsert": true,
"script": {
"inline": "if (ctx.op == \"create\") ctx._source.numbers = newNumbers; else ctx._source.numbers += updatedNumbers",
"params": {
"newNumbers": [1,2,3],
"updatedNumbers": [55]
}
},
"upsert": {}
}
If you call the above command and the index doesn't exist, it will create it, together with the newNumbers values in the new documents. If you call again the exact same command the numbers values will become 1,2,3,55.
And in your case you are missing "upsert": {} part.
As Andrei suggested I was missing the upsert part, changing the function to:
public void scriptedUpsert(String key, String parent, String scriptSource, Map<String, ? extends Object> parameters) {
Script script = new Script(scriptSource, ScriptType.INLINE, null, parameters);
UpdateRequest request = new UpdateRequest(index, type, key);
request.scriptedUpsert(true);
request.script(script);
request.upsert("{}"); // <--- The change
if (parent != null) {
request.parent(parent);
}
this.bulkProcessor.add(request);
}
Fix it.
I want to create a Java Application, which creates an user account.
After this, the user should be able to login on my website.
I need a Java method to generate a hash, which is supported by PHP.
In PHP I always used this function to generate a hash:
public function hashPassword($password){
$options = [
'cost' => 11,
];
$password."<br>";
$hash = password_hash($password, PASSWORD_BCRYPT, $options)."<br>";
return $hash;
}
How can I do this in Java, when ...
I use this in PHP, to validate the password
public function checkPassword($password, $hash){
if (password_verify($passwordFromPost, $hash)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
}
PS: to generate the $hash, I use the first function.
If anything isn't correct, please correct my code, because I'm new in Java