Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
Does anyone know how I can include encryption and decryption in my code? I am using FileInput and FileOutput Stream for serialized files. I have an arraylist of students, and I have an arraylist of books. I can save and read them from their individual files. But for security, I want to encrypt and decrypt them. How do I do that?
private static void ReadBook() {
try {
FileInputStream fi = new FileInputStream("bookData.ser");
ObjectInputStream oi = new ObjectInputStream(fi);
bookList = (ArrayList<Book>) oi.readObject();
oi.close();
} catch (Exception e) {
e.printStackTrace();
}
}
protected static void SaveBook(ArrayList<Book> books) {
ArrayList<Book> tempbookList = books;
try {
FileOutputStream fs = new FileOutputStream("bookData.ser");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.reset();
os.writeObject(tempbookList);
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void ReadStudent() {
try {
FileInputStream fi = new FileInputStream("studentData.ser");
ObjectInputStream oi = new ObjectInputStream(fi);
studentList = (ArrayList<Student>) oi.readObject();
oi.close();
} catch (Exception e) {
e.printStackTrace();
}
}
protected static void SaveStudent(ArrayList<Student> students) {
ArrayList<Student> tempstudentList = students;
try {
FileOutputStream fs = new FileOutputStream("studentData.ser");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.reset();
os.writeObject(tempstudentList);
os.close();
} catch (Exception e) {
e.printStackTrace();
}
What you want isn't possible without an external secret. The problem is, you can 'encrypt' this, but it's not actually encryption (just obfuscation) unless there is a key involved, and the point of a key is: If you know it, you can decrypt it.
So, where does the key come from? You can't hardcode it into your source (sources can be decompiled or just opened with a hex editor), you can't load it off of a file (because anybody that can fetch the encrypted file can also fetch the file with the key in it and thus now they have all they need to decrypt the data). You can try to add layers into this, but it's turtles all the way down: If the application itself can obtain the secret, and the unauthorized person has full access to the computer that the application runs on, this is just not possible.
One way out is to actually say that the owner of the computer doesn't own it - this gets us into messing with security chips such as apple's T2 or the windows ecosystem's TPM. You can't interact with these from java without native code.
Another much simpler way out is to ensure that the application cannot decrypt the data unassisted. Simply ask the user for a password every time they start up the app. Then as long as the app is open, any hacker can just memorydump the VM and get the data, but once the app is closed and the memory is cleaned up (a little tricky at times), it's a secret again.
First think about those more high flying concepts of exactly which scenarios you want to protect and how you want to protect them. Only after that is it time to think about how you implement such things.
Seriously: Write down james bond scenarios. Rate them according to how much you want to protect against them (hint: It won't come for free).
For example: If the computer is stolen, I want to be able to say that as long as the power was pulled and the thieves aren't doing crazy stuff such as pulling the memory chips and blasting a can of CO2 at it to freeze them - I want the data to be gone - that's workable. But note that this is far better achieved by the user themselves: Have the OS apply full disk encryption. They'll do a far better job than you can, and those DO get to enjoy the benefits of security chips (TPM or T2, for example).
Another example: "Someone with a little knowledge and access to the room, I want to prevent these people from looking at the data". That's VERY tricky, they can use physical keyloggers (stick a tiny little USB dongle in between keyboard and system, or install a camera pointing at screen and keyboard) or just open the computer up and install a custom boot. If you want to keep those out, we need to talk about securing the case, or protecting the room itself with physical alarm systems, custom devices, or other extreme measures. It's good to know that this particular threat (so-called 'evil maid attack') is most likely not what you want to protect against (security involves tradeoffs. To properly assess tradeoffs, you need these scenarios).
Related
This question already has answers here:
What is object serialization?
(15 answers)
Closed 2 years ago.
I'm trying to make a Client/Server chat application using java. I'm pretty new to using sockets to communicate between applications. I've decided to use ObjectInput/ObjectOutput streams to send objects between the client and server.
I'm trying to send user data to the server when the client connects to the socket. Here is the code.
Server:
private void startServer() {
try {
this.server = new ServerSocket(port);
this.socket = server.accept();
ChatUtils.log("Accepted a new connection!");
this.output = new ObjectOutputStream(socket.getOutputStream());
this.input = new ObjectInputStream(socket.getInputStream());
try {
User user = (User) input.readObject();
ChatUtils.log(user.getDisplayName() + " (" + user.getUsername() + ") has connected!");
} catch (ClassNotFoundException e) {
}
} catch (IOException e) {
e.printStackTrace();
}
}
Client:
public void connectToServer(int port) {
try {
server = new Socket("127.0.0.1", port);
this.port = port;
this.objectOutput = new ObjectOutputStream(server.getOutputStream());
System.out.println("Connected to a server on port " + port + "!");
objectOutput.writeObject(user);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Everything works fine, but I'm looking for some clarification as to how the methods ObjectOutputStream#writeObject() and ObjectInputStream#readObject() work.
When I write the line User user = (User) input.readObject();, it reads the object as a User object. Would this only attempt to convert "User" objects that are send from the client's ObjectOutputStream?
As this method is only called once, can I cast the input stream to other objects if I send those objects to the server from the output stream? Ex: String message = (String) input.readObject();.
What would happen if I sent multiple objects to the server from the output stream at once?
4)In example one, I try to read the "user" object. What happens if there are two or more objects waiting to be read? How do I determine which object is which? Ex:
// Client
public void connectToServer() {
String message = "Hello server!"
User user = new User("John Doe", "jdoe123");
output.writeObject(user);
output.writeObject(message);
}
If someone could answer these questions, that'd be great. Thanks so much!
Every time you call .writeObject, java will take the object you specified and will serialize it.
This process is a hacky, not-recommended strategy.
Java will first attempt to break down the object you passed into its constituent parts. It will do this, hopefully, with some assistance from the class definition (the class that the object is, i.e. the one returned by theObjectWritten.getClass(). any class def that implements Serializable claims to be designed for this and gets some additional help, but the mechanism will try with reflection hacks if you don't.
Then, the constituent parts are sent along the wire (that is, take the object, and any fields that are primitives can just be sent; ObjectOutputStream knows how to send an int intrinsically, for example. Any other types are sent by, in turn, asking THAT object's class to do so). For each object, java also sends the so called 'serial version uid', which is a calculated number and changes any time any so-called signature changes anywhere in the class. It's a combination of the class's package, name, which class it extends, which interfaces it implements, and every name and type of every field (and possibly every name, return type, param types, and exception types thrown for every method).
So, now we have a bundle, consisting of:
The name of the class (e.g. com.foo.elliott.User)
The serialversionUID of the class
the actual data in User. If User contained any non-primitive fields, apply this process recursively.
Then this is all sent across the wire.
Then on receipt, the receiving code will take all that and pack it back into a User object. This will fail, unless the receiving end actually has com.foo.elliott.User on the classpath, and that def has the same serial version UID.
In other words, if you ever update this class, the transport fails unless the 'other side' also updates.
You can manually massage this stuff by explicitly declaring the serialVersionUID, but note that e.g. any created fields just end up being blank, even if the constructor ordinarily would ensure they could never be.
You can also fully manually manage all this by overriding some specific 'voodoo' methods (a method with a specific name. Java is ordinarily not structurally typed, but these relics of 25 years in the past, such as psv main and these methods, are the only structurally typed things in all of java).
In addition, the binary format of this data is more or less 'closed', it is not obvious, not easy to decode, and few libraries exist.
So, the upshot is:
It is a finicky, error ridden process.
Updating anything you serialize is a pain in the behind.
You stand no chance of ever reading this wire protocol with any programming language except java.
The format is neither easy to read, nor easy to work with, nor particularly compact.
This leads to the inevitable conclusion: Don't use ObjectOutputStream.
Instead, use other serialization frameworks that weren't designed 25 years ago, such as JSON or XML marshallers like google's GSON or Jackson.
NB: In addition your code is broken. Whenever you make a resource, you must also close it, and as code may exit before you get there, the only solution is a special construct. This is how to do it:
try (OutputStream out = socket.getOutputStream()) { .. do stuff here .. }
note that no matter how code 'escapes' from the braces, be it normally (run to the end of it), or because you return/break/continue out of it, or an exception is thrown, the resource is closed.
This also means assigning resources (anything that implements AutoClosable, like Socket, InputStream, and OutputStream, does so) to fields is broken, unless you make the class itself an AutoClosable, and whomever makes it, does so in one of these try-with blocks.
Finally, don't catch exceptions unless you can actually handle them, and 'printStackTrace' doesn't count. If you have no idea how to handle it, throw it onwards; declare your methods to 'throws IOException'. main can (and should!) generally be declared as throws Exception. If truly you can't, the 'stand in', forget-about-it correct way to handle this, and update your IDE to generate this instead of the rather problematic e.printStackTrace(), is this:
catch (ThingICantHandleException e) {
throw new RuntimeException("unhandled", e);
}
Not doing so means your code continues whilst the process is in an error state, and you don't want that.
I'm still working on the project I already needed a bit of help with:
JavaFX - TableView doesn't update items
Now I want to understand how this whole Serialization process in Java works, because unfortunately, I don't really get it now.
Before I go on, first of all, I'm a student, I'm not a professional. Second, I'm neither familiar with using DBs, nor XML or JSON, so I'd just like to find solution to my approach, no matter how inelegant it might be in the end, it just needs to work. So please don't feel offended if I just reject any advice in using other techniques.
So here's what I want:
Saving three different class objects to separate files BUT maintaining backward compatibility to each of it. The objects are Settings, Statistics and a "database" object, containing all words in a list added to it. In the future I may add more statistics or settings, means adding new variables, mostly type of IntegerProperty or DoubleProperty.
Now the question is: is it possible to load old version saved files and then during the process just initiate new variables not found in the old version with just null but keep the rest as it has been saved?
All I know is that the first thing to do so is not to alter the serialVersionUID.
Another thing would be saving the whole Model object (which contains the three objects mentioned before), so I just have to implement stuff for one class instead of three. But how would that work then concerning backward compatibility? I mean the class itself would not change but it's attributes in their own class structure.
Finally, what approach should I go for? And most of all, how do I do this and maintaning backward compatibilty at the same time? I do best with some concrete examples rather than plain theory.
Here are two example methods, if it's of any help. I already have methods for each class to write and read an object.
public static void saveModel(Model model, String destination) throws IOException
{
try
{
fileOutput = new FileOutputStream(destination);
objectOutput = new ObjectOutputStream(fileOutput);
objectOutput.writeObject(model);
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (objectOutput != null)
try
{
objectOutput.close();
}
catch (IOException e) {}
if (fileOutput != null)
try
{
fileOutput.close();
}
catch (IOException e) {}
}
}
public static Settings readSettings(String destination) throws IOException, FileNotFoundException
{
Settings s = null;
try
{
fileInput = new FileInputStream(destination);
objectInput = new ObjectInputStream(fileInput);
Object obj = objectInput.readObject();
if (obj instanceof Settings)
{
s = (Settings)obj;
}
}
catch (IOException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
finally
{
if (objectInput != null) try { objectInput.close(); } catch (IOException e) {}
if (fileInput != null) try { fileInput.close(); } catch (IOException e) {}
}
return s;
}
Tell me if you need more of my current code.
Thank you in advance!
... you must be this tall
Best advice for Serialisation is to avoid it for application persistence, especially if backwards compatibility is desired property in your application.
Answers
Is it possible to load old version saved files and then during the process just initiate new variables not found in the old version with just null but keep the rest as it has been saved?
Yes. Deserialising objects saved using previous versions of the class into a new version of this class will work only if:
fully qualified name of the class has not changed (same name and package)
previous and current class have exactly the same serialVersionUID; if one of the versions is missing it, it will be calculated as a 'hash' of all fields and methods and upon a mismatch deserialisation will fail.
inheritance hierarchy has not changed for that class (the same ancestors)
no fields have been removed in the new version of the class
no fields have become static
no fields have become transient
I just have to implement stuff for one class instead of three. But how would that work then concerning backward compatibility?
Yes. Providing that all classes of all fields of Model and Model class itself adhere to the rules above.
Finally, what approach should I go for? And most of all, how do I do this and maintaning backward compatibilty at the same time?
Yes, as long as you can guarantee all of the above rules forever, you will be backwards compatible.
I am sure you can appreciate that forever, or even for next year can be very hard to guarantee, especially in software.
This is why people do application persistence using more robust data exchange formats, than binary representation of serialised Java objects.
Raw data for the table, could be saved using anything from CSV file to JSON docs stored as files or as documents in NoSQL database.
For settings / config have a look at Java's Properties class which could store and load properties to and from *.properties or *.xml files or separately have a look at YAML.
Finally for backwards compatibility, have a look at FlatBuffers
The field of application persistence is very rich and ripe, so happy exploring.
I want to check if a Windows Workstation is logged on or off. I've found a solution in C#:
public class CheckForWorkstationLocking : IDisposable
{
private SessionSwitchEventHandler sseh;
void SysEventsCheck(object sender, SessionSwitchEventArgs e)
{
switch (e.Reason)
{
case SessionSwitchReason.SessionLock: Console.WriteLine("Lock Encountered"); break;
case SessionSwitchReason.SessionUnlock: Console.WriteLine("UnLock Encountered"); break;
}
}
public void Run()
{
sseh = new SessionSwitchEventHandler(SysEventsCheck);
SystemEvents.SessionSwitch += sseh;
}
#region IDisposable Members
public void Dispose()
{
SystemEvents.SessionSwitch -= sseh;
}
#endregion
}
but at the end I'm going to need this boolean in my Java Program.
I already tried the following:
I started both programs and C# writes into a file from where I can check all few seconds if the data has changed or not from java (don't need to say that this solution is just slow and insufficient)
Another solution would be :
Java starts the C# .exe which waits until Java connects to it through sockets and they share the data over the open connection.
Is there a better way to solve this with less effort than with this socket interface solution?
You don't have to go to any complicated lengths to get this done. It can be quite simple.
Save the boolean into a file in C#, then have a file watcher watching the directory in Java. If there is a change it can read the file in Java and find the value of the boolean. Such a solution would not be expensive and eat up a lot of CPU cycles, like a solution where you had a while loop that checked the file would be.
The beginnings of the Java code can be as simple as
import static java.nio.file.StandardWatchEventKinds.*;
Path dir = ...;
try {
WatchKey key = dir.register(watcher,
ENTRY_CREATE,
ENTRY_DELETE,
ENTRY_MODIFY);
} catch (IOException x) {
System.err.println(x);
}
There are lots of possible solutions to this issue. My personal preference would be to use a message queue to post messages between the applications. (http://zeromq.org/ is light and would be my recommendation)
The advantage of this approach is the two applications are decoupled and and its not relying on the filesystem which is notoriously prone to errors.
To call a function that is written in C# (or any .NET library function) from Java, you can use JNI.
However, all JNI will do is get you to C/C++. You will need to write a simple managed C++ object that can forward request from the unmanaged side to the .NET library.
Example Here
I have a process which needs to be run through Java and, unfortunately the password needs to be given to the process in plain-text.
Since the event is so transient and we are working behind massive firewalls, I am actually not worried about the password being transmitted to a subprocess like this. What I am a little worried about is that the Process and ProcessBuilder classes only take commands as String objects, not char[] arrays. So, I have to rely on the garbage collector to destroy the String objects at its discretion, allowing someone to possibly take a heap dump of my program later and get a password.
Its a remote possibility, but I am looking for:
A better way to start a sub process that does not use String objects, but char[]
A way to ensure a String object is properly destroyed after it is used.
(Just to note, due to how this process takes in commands, submitting the password with the inital command is the only way to interact with the sub-process -- see this: Java seems to be sending carriage returns to a sub-process? comments section in original post)
NOTE- The password is not going to the Main() function via commandline. The password is collected using swing JPasswordField, then being written to the ProcessBuilder command array.
IDEA-- I wonder if there is a way through reflection to get the private final char[] value from the String and erase it?
I pursued my idea of using reflection to erase the String.value parameter manually as a means of object destruction. I think it will due!
private void destroyMe(String destroyMe) {
try {
int len = destroyMe.length();
Field f = destroyMe.getClass().getDeclaredField("value");
f.setAccessible(true);
char[] stars = new char[len];
Arrays.fill(stars, '*');
f.set(destroyMe, stars);
f.setAccessible(false);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
Putting the password on the command line is discouraged for security reasons.
If someone has access to your program to take a heap dump, then they can instead just do a 'ps' command and view the password directly. I am sure something similar exists in Windows.
If you were running on a linux system, you might consider configuring sudo to allow your program to run the other program with elevated privileges.
Has anyone ever persisted a training set for CI-Bayes? I have sample code from this site: http://www.theserverside.com/news/thread.tss?thread_id=49773
here is the code:
FisherClassifier fc=new FisherClassifierImpl();
fc.train("The quick brown fox jumps over the lazy dog's tail","good");
fc.train("Make money fast!", "bad");
String classification=fc.getClassification("money", "unknown"); // should be "bad"
so I need to be able to store the training set in a local file.
Has anyone ever done this before?
To persist a java Object in a local file, the Object must first implement the Serializable interface.
import java.io.Serializable;
public class MyClass implements Serializable {...
Then, the class from which you would like to persist this training set, should include a method like:
public void persistTrainingSet(FisherClassifier fc) {
String outputFile = <path/to/output/file>;
try {
FileOutputStream fos = new FileOutputStream(outputFile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(fc);
oos.close();
}
catch (IOException e) {
//handle exception
}
finally {
//do any cleaning up
}
}
I have. After doing a couple projects with CI-Bayes, I would recommend you look elsewhere (of course this was a long time ago). It is a very bad idea to use an inference engine that needs to be trained before each use and if you really consider the issue of state management, it's complicated (e.g. do you want to just store the training data? or perhaps the trained distributions? chains?).
CI-Bayes is also kind of a convoluted codebase. It was modeled off some Python code that appeared in a book about intelligence. The Java version is not very well designed. It also does not use TDD, does not really have JavaDoc to speak of.
That said, you can get a simple classifier going pretty quickly. The longer term goal is the one you asked about though.