Java platform independent encryption - java

I am currently using Jasypt for my web application. It works fine, but the encryption is different depending which server it is hosted on.
For this reason, I can't just get the data in the live DB and use it for debugging in my dev environment. It would be helpful, but I can live without it.
What worries me is that at the moment I am using a hosting provider. All has been ok so far, but I worry that if at some point they replace the server, or move my application on to another one, the encrypted data ( such as emails and passwords for the login, and more ) will not be encrypted in the same way and all the data will become unusable.
Does anybody know an alternative to Jasypt which is platform independent?
Or is there a way to make Jasypt itself platform independent?
Thanks, Dan
PS : I would need a method that has these basic functionalities: string encryption ( reversible ), password encryption ( not reversible but comparable ) and "SHA-1" encryption. Apologies if the terminology in the last paragraph is not the most correct, but I am not an encryption expert at all.
Thanks!
Edited to add code, results and exceptions:
public class Test
{
public static void main ( String [] args )
{
System.out.println ( "String encryption = " + new EncryptionUtil ( ).encryptString ( "test string" ) );
System.out.println ( "Password encryption = " + new EncryptionUtil ( ).encryptPassword ( "test password" ) );
}
}
produces this in the dev environment :
String encryption = ybXukKBN57QSY8ITPgu9RmJQrZP4Py6g
Password encryption = nNX82PuKx5TrqBFSCy6yzNpco7Asov2S
Everytime the output is different, but it is possible to decrypt the string, and compare the password by doing this:
public class Decryption
{
public static void main ( String [] args )
{
System.out.println ( new EncryptionUtil ( ).decryptString ( "ybXukKBN57QSY8ITPgu9RmJQrZP4Py6g" ) );
System.out.println ( new EncryptionUtil ( ).passwordsMatch ( "test password", "nNX82PuKx5TrqBFSCy6yzNpco7Asov2S" ) );
}
}
Which gives this output:
test string
true
This is the encryption util class that I created:
public class EncryptionUtil
{
private String password = "<<=Encryption-Password=>>";
// ============================================================ Encrypt password string
public String encryptPassword ( String pwd )
{
if ( null != pwd && ! "".equals ( pwd ) )
{
return new BasicPasswordEncryptor ().encryptPassword ( pwd );
}
else
{
return "";
}
}
// ====================================== Check if password entered matches that stored
public boolean passwordsMatch ( String enteredPassword, String storedPassword )
{
return new BasicPasswordEncryptor().checkPassword ( enteredPassword, storedPassword );
}
//===================================================================== Encrypt string
public String encryptString ( String text )
{
if ( null != password && ! "".equals ( password ) )
{
BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
textEncryptor.setPassword ( password );
return textEncryptor.encrypt ( text );
}
else
{
return "";
}
}
// ===================================================================== Decrypt string
public String decryptString ( String text )
{
try
{
if ( null != text && ! "".equals ( text ) )
{
BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
textEncryptor.setPassword ( password );
return textEncryptor.decrypt ( text );
}
else
{
return "";
}
}
catch ( Exception e )
{
return text;
}
}
// =============== Encrypt email. Used for login and registration only, not decryptable
public String encryptEmail ( String email )
{
if ( null != email && ! "".equals ( email ) )
{
return new String ( new Digester("SHA-1").digest ( email.getBytes () ) );
}
else
{
return "";
}
}
}
The same in the LIVE environment gives me this:
String encryption = L/UlkJjYhLnYiov7XeDjb9W7+k8Gduvz
Password encryption = P+LJM7VJHu/hudSQOrmvcvV/DrzCv+pj
When I try to decrypt the string and check the password, I get this:
public class Decryption
{
public static void main ( String [] args )
{
System.out.println ( new EncryptionUtil ( ).decryptString ( "L/UlkJjYhLnYiov7XeDjb9W7+k8Gduvz" ) );
System.out.println ( new EncryptionUtil ( ).passwordsMatch ( "test password", "P+LJM7VJHu/hudSQOrmvcvV/DrzCv+pj" ) );
}
}
The result with the strings obtained from LIVE ( those above ) gives this:
test string
false
This time the encryption of the string works ( I had it not working in the past, I am a bit surprised and confused to be honest ), but the password fails.
New edit - some strings, when encrypted, end with ==. The strings that do not have "==" at the end, are decryptable across systems. Those which do do not work. Maybe this can be a clue?

I am not sure what the problem was - anyway I managed to solve it with a random attempt which somehow worked...
If anybody finds him / her self in the same situation, an attempt ( lucky random one in my case ) is to change the password used for the text encryptor.
I cannot give any explanation on why it worked.

You should take a look at BouncyCastle
There´s an example here

Related

How to efficiently check if read line from Buffered reader contains a string from an enum list

I am a computer science university student working on my first 'big' project outside of class. I'm attempting to read through large text files (2,000 - 3,000 lines of text), line by line with buffered reader. When a keyword from a list of enums is located, I want it to send the current line from buffered reader to its appropriate method to be handled appropriatley.
I have a solution, but I have a feeling in my gut that there is a much better way to handle this situation. Any suggestions or feedback would be greatly appreciated.
Current Solution
I am looping through the the list of enums, then checking if the current enum's toString return is in the current line from buffered reader using the String.contains method.
If the enum is located, the enum is used in a switch statement for the appropriate method call. (I have 13 total cases just wanted to keep the code sample short).
try (BufferedReader reader = new BufferedReader(new FileReader(inputFile.getAbsoluteFile()))){
while ((currentLine = reader.readLine()) != null) {
for (GameFileKeys gameKey : GameFileKeys.values()) {
if (currentLine.contains(gameKey.toString())) {
switch (gameKey) {
case SEAT -> seatAndPlayerAssignment(currentTableArr, currentLine);
case ANTE -> playerJoinLate(currentLine);
}
}
}
}
}
Previous Solution
Originally, I had a nasty list of if statements checking if the current line contained one of the keywords and then handled it appropriatley. Clearly that is far from optimal, but my gut tells me that my current solution is also less than optimal.
try (BufferedReader reader = new BufferedReader(new FileReader(inputFile.getAbsoluteFile()))){
while ((currentLine = reader.readLine()) != null) {
if(currentLine.contains(GameFileKey.SEAT){
seatAndPlayerAssignment(currentTableArr, currentLine);
}
else if(currentLine.contains(GameFileKey.ANTE){
playerJoinLate(currentLine);
}
}
}
Enum Class
In case you need this, or have any general feedback for how I'm implementing my enums.
public enum GameFileKeys {
ANTE("posts ante"),
SEAT("Seat ");
private final String gameKey;
GameFileKeys(String str) {
this.gameKey = str;
}
#Override
public String toString() {
return gameKey;
}
}
I cannot improve over the core of your code: the looping on values() of the enum, performing a String#contains for each enum object’s string, and using a switch. I can make a few minor suggestions.
I suggest you not override the toString method on your enum. The Object#toString method is generally best used only for debugging and logging, not logic or presentation.
Your string passed to constructor of the enum is likely similar to the idea of a display name commonly seen in such enums. The formal enum name (all caps) is used internally within Java, while the display name is used for display to the user or exchanged with external systems. See the Month and DayOfWeek enums as examples offering a getDisplayName method.
Also, an enum should be named in the singular. This avoids confusion with any collections of the enum’s objects.
By the way, looks like you have a stray SPACE in your second enum's argument.
At first I thought it would help to have a list of all the display names, and a map of display name to enum object. However, in the end neither is needed for your purpose. I kept those as they might prove interesting.
public enum GameFileKey
{
ANTE( "posts ante" ),
SEAT( "Seat" );
private String displayName = null;
private static final List < String > allDisplayNames = Arrays.stream( GameFileKey.values() ).map( GameFileKey :: getDisplayName ).toList();
private static final Map < String, GameFileKey > mapOfDisplayNameToGameFileKey = Arrays.stream( GameFileKey.values() ).collect( Collectors.toUnmodifiableMap( GameFileKey :: getDisplayName , Function.identity() ) );
GameFileKey ( String str ) { this.displayName = str; }
public String getDisplayName ( ) { return this.displayName; }
public static GameFileKey forDisplayName ( final String displayName )
{
return
Objects.requireNonNull(
GameFileKey.mapOfDisplayNameToGameFileKey.get( displayName ) ,
"None of the " + GameFileKey.class.getCanonicalName() + " enum objects has a display name of: " + displayName + ". Message # 4dcefee2-4aa2-48cf-bf66-9a4bde02ac37." );
}
public static List < String > allDisplayNames ( ) { return GameFileKey.allDisplayNames; }
}
You can use a stream of the lines of your file being processed. Just FYI, not necessarily better than your code.
public class Demo
{
public static void main ( String[] args )
{
Demo app = new Demo();
app.demo();
}
private void demo ( )
{
try
{
Path path = Demo.getFilePathToRead();
Stream < String > lines = Files.lines( path );
lines.forEach(
line -> {
for ( GameFileKey gameKey : GameFileKey.values() )
{
if ( line.contains( gameKey.getDisplayName() ) )
{
switch ( gameKey )
{
case SEAT -> this.seatAndPlayerAssignment( line );
case ANTE -> this.playerJoinLate( line );
}
}
}
}
);
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
}
private void playerJoinLate ( String line )
{
System.out.println( "line = " + line );
}
private void seatAndPlayerAssignment ( String line )
{
System.out.println( "line = " + line );
}
public static Path getFilePathToRead ( ) throws IOException
{
Path tempFile = Files.createTempFile( "bogus" , ".txt" );
Files.write( tempFile , "apple\nSeat\norange\nposts ante\n".getBytes() );
return tempFile;
}
}
When run:
line = Seat
line = posts ante

HashMap login system with string variables in java database [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 1 year ago.
Previously I created a login system which used a HashMap, but no database. I then ran into the problem of not being able to change the passwords of the system, as they would be reset everytime I booted up the program.
It was like this:
HashMap<String, String> credentials = new HashMap<String, String>();
UserData() {
credentials.put("Manager", "adminpass");
credentials.put("Employee", "employeepass");
credentials.put("Customer", "customerpass");
}
I then realised I want to use text files to store the passwords, so I could edit them and the changes would take effect.
So I created 3 text files. adminpass.txt, employeepass.txt, customerpass.txt
They all contain the passwords which are 'adminpass', 'employeepass', 'customerpass'
With the previous system, I used .equals to compare the password of user input and the real password as it was a string. Now it's a variable, so I am using ==.
Here is my code for logging in:
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == authenticateButton) {
String roleID = usernameField.getText();
String password = String.valueOf(((JPasswordField) passwordField).getPassword());
if (credentials.containsKey(roleID)) {
if (credentials.get(roleID) == password) {
messageLabel.setForeground(Color.green);
messageLabel.setText("Login successful");
frame.dispose();
m.launch(roleID);
} else {
messageLabel.setForeground(Color.red);
messageLabel.setText("Incorrect password");
}
} else {
messageLabel.setForeground(Color.red);
messageLabel.setText("Incorrect username");
}
}
}
});
I also have read from the text files on startup, assigning what the system has read from the files to the adminpass, employeepass, and customerpass variables.
Everytime I login I get 'incorrect password' even though they're correct.
So I decided to do
System.out.println(credentials.get(roleID))
And it just returns null.
I'm completely confused here, I am grateful if anyone can help or point me in the right direction!
Thanks!
EDIT: when i use .equals(password), i get
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because the return value of "java.util.HashMap.get(Object)" is null
This syntax makes no sense to me:
UserData() {
You have not provided quite enough detail to pinpoint your problem. But this error message:
"java.util.HashMap.get(Object)" is null
… tells us you likely have a problem with populating your Map.
Map.of
I suggest starting with a simple hard-coded map, to test your code. Take baby steps, building up your app piece by piece.
package work.basil.example.authenticate;
import java.util.Map;
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
Map < String, String > credentials =
Map.of(
"Manager" , "adminpass" ,
"Employee" , "employeepass" ,
"Customer" , "customerpass"
);
boolean authenticatedManager = credentials.get( "Manager" ).equals( "adminpass" );
boolean authenticatedEmployee = credentials.get( "Employee" ).equals( "employeepass" );
boolean authenticatedCustomer = credentials.get( "Customer" ).equals( "customerpass" );
System.out.println( "credentials = " + credentials );
System.out.println( "authenticatedManager = " + authenticatedManager );
System.out.println( "authenticatedEmployee = " + authenticatedEmployee );
System.out.println( "authenticatedCustomer = " + authenticatedCustomer );
}
}
When run.
credentials = {Employee=employeepass, Customer=customerpass, Manager=adminpass}
authenticatedManager = true
authenticatedEmployee = true
authenticatedCustomer = true
After getting that to work, then replace Map.of hard-coding with a Map populated from your text file or database.
By the way, I'll ignore the issue of saving passwords in plain text. That is obviously the wrong way to manage authentication. I assume you are just learning/practicing, not doing real work for production use.
Populating a map
Here is how to populate a map from this example text file:
Scott,tiger
Alice,password123
Bob,letmein
Example code using NIO.2. See tutorial by Oracle.
String pathText = "/Users/basilbourque/cred.txt";
Path path = Paths.get( pathText );
Map < String, String > tempCredentials = new HashMap <>();
try ( BufferedReader reader = Files.newBufferedReader( path , StandardCharsets.UTF_8 ) )
{
String line = null;
while ( ( line = reader.readLine() ) != null )
{
System.out.println( line );
String[] parts = line.split( "," );
String user = Objects.requireNonNull( parts[ 0 ] ).strip();
String pw = Objects.requireNonNull( parts[ 1 ] ).strip();
if ( user.isBlank() || pw.isBlank() ) { System.out.println( "Add code here to deal with invalid blank inputs. " ); }
tempCredentials.put( user , pw );
}
}
catch ( IOException x )
{
System.err.format( "IOException: %s%n" , x );
}
Map < String, String > credentials = Map.copyOf( tempCredentials ); // Make an unmodifiable map, copied from temporary map.
System.out.println( "credentials = " + credentials );
When run.
Scott,tiger
Alice,password123
Bob,letmein
credentials = {Bob=letmein, Alice=password123, Scott=tiger}
Testing equality
You said:
so I am using ==.
Use == syntax only when asking if two references point to the very same object, the very same chunk of memory.
More commonly you want to compare the content of the objects to see if they are equivalent. For that, use the equals method or some similar method.

how to fetch correctly the data from the a table in mysql which contains Italian,Japanese and Russian characters

I have a table with UTF8 charset. The columns are considered utf8_general_ci. I am reading the data using prepared statement but they are not shown correctly. The data inside the table is not readable too. I need to write a code in a way that they are human readable. I have tested many methods which all failed.
For the Connection property I used "?useUnicode=true&characterEncoding=UTF8";
String city=resultset.getString("city");
byte[] data = city.getBytes();
String valueCity = new String(data, "UTF-8"); // Or String valueCity = new String(data, StandardCharsets.UTF_8);
I see something like "&#21517 ; & #21476 ;& #23627; & #24066;" in my table but I need to read or write them like 名古屋市.
Any suggestions that I may handle this problem which is a pain on my neck?
thanks a million in advance
Maybe it is resultset.getString("city") what is your problem here. You already receive the data as a string. The byte representation of that string is likely not utf-8. What's the type of resultset?
Are you sure you opened your database connection with characterEncoding=utf8? You need to set connectionProperties="useUnicode=yes;characterEncoding=utf8;"
Stackoverflow
Something, not MySQL, is generating "html entities" such as 名. Find where those are coming from and undo it.
Since those entities are probably already stored in the table, that needs to be undone, too.
The html entities should render correctly in any browser. Are you trying to use them in some other context?
It might help to check the resultset.getBytes(..) instead of getString first
Finally I found the code:
public static String unescapeXML( final String xml )
{
Pattern xmlEntityRegex = Pattern.compile( "&(#?)([^;]+);" );
// Matcher requires a StringBuffer instead of a StringBuilder
StringBuffer unescapedOutput = new StringBuffer( xml.length() );
Matcher m = xmlEntityRegex.matcher( xml );
Map<String,String> builtinEntities = null;
String entity;
String hashmark;
String ent;
int code;
while ( m.find() ) {
ent = m.group(2);
hashmark = m.group(1);
if ( (hashmark != null) && (hashmark.length() > 0) ) {
code = Integer.parseInt( ent );
entity = Character.toString( (char) code );
} else {
//must be a non-numerical entity
if ( builtinEntities == null ) {
builtinEntities = buildBuiltinXMLEntityMap();
}
entity = builtinEntities.get( ent );
if ( entity == null ) {
//not a known entity - ignore it
entity = "&" + ent + ';';
}
}
m.appendReplacement( unescapedOutput, entity );
}
m.appendTail( unescapedOutput );
return unescapedOutput.toString();
}
private static Map<String,String> buildBuiltinXMLEntityMap()
{
Map<String,String> entities = new HashMap<String,String>(10);
entities.put( "lt", "<" );
entities.put( "gt", ">" );
entities.put( "amp", "&" );
entities.put( "apos", "'" );
entities.put( "quot", "\"" );
return entities;
}

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated when trying to session.getPeerCertificateChain()

I am pretty new to working with http/certs/etc. I have my own hostnameVerifier set up for an apache httpclient. (Trying to allow FQDN to not match as long as cert FQDN is still internal to our domain - not the best I know - but better than nothing)
It works fine for most of the servers I have tested with, but there are a couple where I get
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
when I try to
session.getPeerCertificateChain().
I am able to view the certificate just fine when I go to the same link in firefox.
Below is the full code for the method.
#Override
public void verify( String arg0, SSLSocket arg1 ) throws IOException
{
String certFQDN = null;
SSLSession session = arg1.getSession();
javax.security.cert.X509Certificate[] certs = session.getPeerCertificateChain();
if ( certs.length > 0 )
{
String name = certs[ 0 ].getSubjectDN().getName();
for ( String s : name.split( "," ) )
{
String part[] = s.split( "=" );
if ( part[ 0 ].trim().equals( "CN" ) )
{
certFQDN = part[ 1 ].trim();
}
}
}
else
{
throw new IOException( "Could not find certificate chain." );
}
if ( !certFQDN.substring( certFQDN.length() - 11 ).equals( ".domain.com" ) )
{
throw new SSLException( "Not an internal host: " + certFQDN );
}
}
#Override public void verify( String arg0, SSLSocket arg1 ) throws IOException {
arg1.getSession();
javax.security.cert.X509Certificate[] certs = session.getPeerCertificateChain();
].getSubjectDN().getName();
) )
);
].trim().equals( "CN" ) )
].trim();
not find certificate chain." );
certFQDN.length() - 11 ).equals( ".domain.com" ) )
internal host: " + certFQDN );
}

Authenticating from Java (Linux) to Active Directory using LDAP WITHOUT servername

Our developers use Java on Linux for various things (like checking membership of groups etc). It works - no problem with that!
The problem is that they have hardcoded the servernames of our Domain Controllers (LDAP-servers) in their code. So now when we need to replace them with newer DCs, they need to change the code.
Active Directory by nature is redundant. The domain name (example: domain.local) is a round-robin of all the DC:s available for our AD.
Is there any way for the developer to NOT specify Domain Controller server names but simply the Active Directory domain name and then their Linux server will find the DC:s available and use whichever one is up and running?
Examples/links appreciated. Thanks!
Obviously, the server name should at least be configurable, not hard coded into the application.
However, you should be able to find the server by looking up a special DNS record, namely a SRV record for _ldap._tcp.DOMAINNAME. The linux servers have to be configured to use the same DNS server as your AD updates.
To determine whether this is feasible, run the command host -t srv _ldap._tcp.DOMAINNAME on your linux server
See also Querying the DNS service records to find the hostname and TCP/IP provides some info on how to look up SRV records in java, and https://community.oracle.com/blogs/kohsuke/2008/06/12/more-active-directory-integration-java
We use the follow code that work on a large amount of systems:
/**
* Detect the default LDAP server
* #return server:port or null
*/
String getDefaultLdapHost() {
try {
Hashtable<String, String> env = new Hashtable();
env.put( "java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory" );
DirContext dns = new InitialDirContext( env );
InetAddress address = InetAddress.getLocalHost();
String domain = address.getCanonicalHostName();
if( domain.equals( address.getHostAddress() ) ) {
//domain is a ip address
domain = getDnsPtr( dns );
}
int idx = domain.indexOf( '.' );
if( idx < 0 ) {
//computer is not in a domain? We will look in the DNS self.
domain = getDnsPtr( dns );
idx = domain.indexOf( '.' );
if( idx < 0 ) {
//computer is not in a domain
return null;
}
}
domain = domain.substring( idx + 1 );
Attributes attrs = dns.getAttributes( "_ldap._tcp." + domain, new String[] { "SRV" } );
Attribute attr = attrs.getAll().nextElement();
String srv = attr.get().toString();
String[] parts = srv.split( " " );
return parts[3] + ":" + parts[2];
} catch( Exception ex ) {
ex.printStackTrace();
return null;
}
}
/**
* Look for a reverse PTR record on any available ip address
* #param dns DNS context
* #return the PTR value
* #throws Exception if the PTR entry was not found
*/
private String getDnsPtr( DirContext dns ) throws Exception {
Exception exception = null;
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while(interfaces.hasMoreElements()) {
NetworkInterface nif = interfaces.nextElement();
if( nif.isLoopback() ) {
continue;
}
Enumeration<InetAddress> adresses = nif.getInetAddresses();
while(adresses.hasMoreElements()) {
InetAddress address = adresses.nextElement();
if( address.isLoopbackAddress() || address instanceof Inet6Address) {
continue;
}
String domain = address.getCanonicalHostName();
if( !domain.equals( address.getHostAddress() ) && (domain.indexOf( '.' ) > 0) ) {
return domain;
}
String ip = address.getHostAddress();
String[] digits = ip.split( "\\." );
StringBuilder builder = new StringBuilder();
builder.append( digits[3] ).append( '.' );
builder.append( digits[2] ).append( '.' );
builder.append( digits[1] ).append( '.' );
builder.append( digits[0] ).append( ".in-addr.arpa." );
try {
Attributes attrs = dns.getAttributes( builder.toString(), new String[] { "PTR" } );
return attrs.get( "PTR" ).get().toString();
} catch( Exception ex ) {
exception = ex;
}
}
}
if( exception != null ) {
throw exception;
}
throw new IllegalStateException("No network");
}

Categories