commit 36d4aaac81cf393ee4b9a7a9d0ffb20b0a42d9a1 Author: Ben Goldsworthy Date: Wed Jun 24 10:50:35 2020 +0100 Initial commit (v1) diff --git a/bin/rmireg.bat b/bin/rmireg.bat new file mode 100755 index 0000000..03b7af3 --- /dev/null +++ b/bin/rmireg.bat @@ -0,0 +1 @@ +javac *.java && start rmiregistry \ No newline at end of file diff --git a/bin/startClient.bat b/bin/startClient.bat new file mode 100755 index 0000000..d14bb34 --- /dev/null +++ b/bin/startClient.bat @@ -0,0 +1 @@ +javac *.java && java AuctionClient \ No newline at end of file diff --git a/bin/startServer.bat b/bin/startServer.bat new file mode 100755 index 0000000..c4d9c2a --- /dev/null +++ b/bin/startServer.bat @@ -0,0 +1 @@ +javac *.java && java AuctionServer \ No newline at end of file diff --git a/src/Auction.java b/src/Auction.java new file mode 100755 index 0000000..4152cc2 --- /dev/null +++ b/src/Auction.java @@ -0,0 +1,106 @@ +/* + * AuctionProg 1.0 + * Copyright © 2016 Ben Goldsworthy (rumps) + * + * A program to facilitate a networked auction system. + * + * This file is part of AuctionProg. + * + * AuctionProg is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AuctionProg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AuctionProg. If not, see . + */ + +/** + ** This class represents the auction server. + **/ + +import java.io.*; +import java.util.*; +import java.security.*; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +/** + ** @author Ben Goldsworthy (rumps) + ** @version 1.0 + **/ +public interface Auction extends java.rmi.Remote { + /** + ** Creates an auction with the given details, generating a new ID for + ** it. + ** + ** @param desc The auction description. + ** @param owner The auction owner/creator. + ** @param startingPrice The auction starting price. + ** @param reserve The auction reserve price. + **/ + public void createAuction(String desc, UserWrapper owner, float startingPrice, float reserve) throws java.rmi.RemoteException; + + /** + ** Removes an auction, provided the user calling the method owns it. + ** If the reserve price was met, also returns the winning bidder. + ** + ** @param id The ID of the auction to remove. + ** @param currentUser The user calling the method. + ** @return The `UserWrapper` of the highest bidder, if applicable. + **/ + public UserWrapper removeAuction(int id, UserWrapper currentUser) throws java.rmi.RemoteException; + + /** + ** Bids on a given auction, provided the bid is more than the + ** current highest price. + ** + ** @param id The ID of the auction in question. + ** @param bidder The user bidding on the auction. + ** @param price The amount bid. + **/ + public void bidOnAuction(int id, UserWrapper bidder, float price) throws java.rmi.RemoteException; + + /** + ** Accessor Method. Retrieves a list of all the auctions. + ** + ** @return An `ArrayList` of `AuctionWrapper`s. + **/ + public ArrayList getAuctions() throws java.rmi.RemoteException; + + /** + ** Accessor Method. Gets a user, or creates a new one if non + ** exists with the given details. + ** + ** @param name The user's name. + ** @param email The user's email address. + ** @return The relevant `UserWrapper`. + **/ + public UserWrapper getUser(String username) throws java.rmi.RemoteException; + + public UserWrapper registerUser(String name, String email, String username) throws java.rmi.RemoteException; + + public void close() throws java.rmi.RemoteException; + + public PublicKey getPublicKey() throws java.rmi.RemoteException; + public void sendPublicKey(PublicKey key, String username) throws java.rmi.RemoteException; + + /** + ** Accessor Method. Gets the status resulting from the last action + ** attempted. + ** + ** @return The status message. + **/ + public String getStatusofLast() throws java.rmi.RemoteException; + + public byte[] challengeServer(byte[] challenge) throws java.rmi.RemoteException; + + public byte[] getChallenge() throws java.rmi.RemoteException; + public boolean returnChallenge(byte[] retChal, String username) throws java.rmi.RemoteException; +} + diff --git a/src/AuctionClient.java b/src/AuctionClient.java new file mode 100755 index 0000000..9186f7f --- /dev/null +++ b/src/AuctionClient.java @@ -0,0 +1,342 @@ +/* + * AuctionProg 1.0 + * Copyright © 2016 Ben Goldsworthy (rumps) + * + * A program to facilitate a networked auction system. + * + * This file is part of AuctionProg. + * + * AuctionProg is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AuctionProg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AuctionProg. If not, see . + */ + +/** + ** This class presents the client view for interacting with the program. + **/ + +import java.io.*; +import java.rmi.Naming; +import java.rmi.RemoteException; +import java.net.MalformedURLException; +import java.rmi.NotBoundException; +import java.util.*; +import java.util.Scanner; +import java.util.regex.Pattern; +import java.security.*; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +/** + ** @author Ben Goldsworthy (rumps) + ** @version 1.0 + **/ +public class AuctionClient { + // This regex is used to ensure the email address entered is a valid + // email address format + // (Source: http://stackoverflow.com/a/153751/4580273) + private static final Pattern rfc2822 = Pattern.compile("^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$"); + + /** + ** Displays the UI. + ** + ** @param args Command-line arguments. + **/ + public static void main(String[] args) { + try { + // Create the reference to the remote object through the + // remiregistry. This comes first because if it fails we can + // skip doing everything else. + Auction a = (Auction) Naming.lookup("rmi://localhost/AuctionService"); + + // Declares some variables that'll be used later on. + Scanner in = new Scanner(System.in); + UserWrapper currentUser = null; + int id; + float price; + + // Authenticates the user, if the program is run with a username + // as an argument. Otherwise, prompts the user to create a new + // user. + currentUser = login(a, (args.length > 0) ? args[0] : "server"); + + while(true) { + // Resets the variables after each run through. + price = 0.0f; + + printOptions(); + + switch(in.nextLine()) { + // This case takes auction details from the user and then + // creates a new auction with those. + case "1": + createNewAuction(a, currentUser); + break; + // This case removes the auction with the given ID, provided it + // is owned by the current user. + case "2": + deleteAuction(a, currentUser); + break; + // This case displays all the currently-available auctions. + case "3": + displayAuctions(a); + break; + // This case places a bid on an auction. + case "4": + placeBid(a, currentUser); + break; + // This case exits the program. + case "5": + System.exit(1); + break; + // The below cases are remote debug commands. + // This case remotely shuts down the server. + case "6": + a.close(); + break; + default: + break; + } + } + } catch (Exception e) { + System.out.println(); + System.out.println("Exception"); + System.out.println(e); + } + System.exit(-1); + } + + private static UserWrapper login(Auction a, String username) throws java.rmi.RemoteException, java.security.NoSuchAlgorithmException, java.security.InvalidKeyException, java.security.SignatureException { + UserWrapper user = null; + + // If the user has run the program with a username argument, + // authenticate that user. + if (!username.equals("server")) { + boolean verifies; + byte[] challenge, serverResponse, userResponse; + Signature signed, signing; + + // Sends the server a number to sign with its private key. + System.out.println("Authenticating server..."); + + challenge = new byte[1024]; + new Random().nextBytes(challenge); + serverResponse = a.challengeServer(challenge); + + signed = Signature.getInstance("SHA1withDSA"); + signed.initVerify(readKey()); + signed.update(challenge); + + verifies = signed.verify(serverResponse); + System.out.println("server signature verifies: " + verifies); + + // Receives a number from the server to sign with the user's + // private key. + System.out.println("Authenticating user '"+username+"'..."); + + challenge = a.getChallenge(); + + signing = Signature.getInstance("SHA1withDSA"); + signing.initSign(readKey(username)); + signing.update(challenge); + userResponse = signing.sign(); + + verifies = a.returnChallenge(userResponse, username); + System.out.println(username+" authenticated by server: " + verifies); + + // Closes the program on authentication fail. + if (!verifies) System.exit(-1); + + // Otherwise, load the user and move on. + user = a.getUser(username); + System.out.println(a.getStatusofLast()); + // If the user has run the program with no arguments, they are + // prompted to create a new user. + } else { + String name = "", email = ""; + Scanner in = new Scanner(System.in); + + while (user == null) { + System.out.print("Enter name: "); + name = in.nextLine(); + + System.out.print("Enter email: "); + while (!rfc2822.matcher(email).matches()) { + email = in.nextLine(); + if (!rfc2822.matcher(email).matches()) System.out.println("\nError: invalid email address\n"); + } + + while (username.equals("server")) { + System.out.print("Enter username ('server' is prohibited): "); + username = in.nextLine(); + } + + user = a.registerUser(name, email, username); + System.out.println(a.getStatusofLast()); + } + + // Upon a successful user creation, new keys are generated and + // exchanged with the server. + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); + SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); + keyGen.initialize(1024, random); + + KeyPair pair = keyGen.generateKeyPair(); + writeKey(pair.getPrivate(), username); + a.sendPublicKey(pair.getPublic(), username); + writeKey(a.getPublicKey(), "server"); + } + return user; + } + + private static void printOptions() { + System.out.println("1\tCreate auction\n2\tDelete auction\n3\tView auctions\n4\tBid on auction\n5\tQuit\n6\tClose server"); + System.out.print("Choose option: "); + } + + private static void createNewAuction(Auction a, UserWrapper currentUser) throws java.rmi.RemoteException { + float startPrice = 0.0f; + float reservePrice = 0.0f; + Scanner in = new Scanner(System.in); + + try { + System.out.print("Enter description: "); + String desc = in.nextLine(); + + System.out.print("Enter starting price: \u00A3"); + startPrice = Float.parseFloat(in.nextLine()); + + while (reservePrice <= startPrice) { + System.out.print("Enter reserve price (must be higher than starting price): \u00A3"); + reservePrice = Float.parseFloat(in.nextLine()); + } + + a.createAuction(desc, currentUser, startPrice, reservePrice); + System.out.println(a.getStatusofLast()); + } catch(NumberFormatException ex){ + System.out.println("\nError: not a valid price\n"); + } + } + + private static void deleteAuction(Auction a, UserWrapper currentUser) throws java.rmi.RemoteException { + int id; + UserWrapper winner; + Scanner in = new Scanner(System.in); + + if (!a.getAuctions().isEmpty()) { + System.out.print("Enter auction number: "); + id = Integer.parseInt(in.nextLine()); + + try { + winner = a.removeAuction(id, currentUser); + System.out.println("\nAuction won by: "+winner.getName()+" <"+winner.getEmail()+">\n"); + } catch(NullPointerException e) { + System.out.println(a.getStatusofLast()); + } + } else { + System.out.println("\nNo auctions available\n"); + } + } + + private static void displayAuctions(Auction a) throws java.rmi.RemoteException { + if (!a.getAuctions().isEmpty()) { + System.out.println("#\tOwner\tPrice\tDesc"); + for (int i = 0; i < 80; i++) System.out.print("-"); + for(AuctionWrapper auction: a.getAuctions()){ + System.out.println(auction.getID()+"\t"+auction.getOwner().getUsername()+"\t\u00A3"+String.format("%.2f", auction.getPrice())+"\t"+auction.getDesc()); + } + System.out.println(""); + } else { + System.out.println("\nNo auctions available\n"); + } + } + + private static void placeBid(Auction a, UserWrapper currentUser) throws java.rmi.RemoteException { + Scanner in = new Scanner(System.in); + + if (!a.getAuctions().isEmpty()) { + try{ + int id; + float price; + + System.out.print("Enter auction number: "); + id = Integer.parseInt(in.nextLine()); + + System.out.print("Enter bid amount: \u00A3"); + price = Float.parseFloat(in.nextLine()); + + a.bidOnAuction(id, currentUser, price); + System.out.println(a.getStatusofLast()); + } catch(NumberFormatException ex){ + System.out.println("\nError: not a valid price\n"); + } + } else { + System.out.println("\nNo auctions available\n"); + } + } + + private static PrivateKey readKey(String username) { + try { + FileInputStream keyfis = new FileInputStream(username + "priv.key"); + byte[] encKey = new byte[keyfis.available()]; + keyfis.read(encKey); + keyfis.close(); + + PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encKey); + + KeyFactory keyFactory = KeyFactory.getInstance("DSA"); + return keyFactory.generatePrivate(privKeySpec); + } catch (Exception e) { + System.out.println(); + System.out.println("Exception"); + System.out.println(e); + return null; + } + } + private static PublicKey readKey() { + try { + FileInputStream keyfis = new FileInputStream("serverpub.key"); + byte[] encKey = new byte[keyfis.available()]; + keyfis.read(encKey); + keyfis.close(); + + X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey); + + KeyFactory keyFactory = KeyFactory.getInstance("DSA"); + return keyFactory.generatePublic(pubKeySpec); + } catch (Exception e) { + System.out.println(); + System.out.println("Exception"); + System.out.println(e); + return null; + } + } + + private static void writeKey(PrivateKey pKey, String username) { + wK(pKey, username, "priv"); + } + private static void writeKey(PublicKey pKey, String username) { + wK(pKey, username, "pub"); + } + private static void wK(Key pKey, String username, String type) { + try { + byte[] key = pKey.getEncoded(); + FileOutputStream keyfos = new FileOutputStream(username+type+".key"); + keyfos.write(key); + keyfos.close(); + } catch (Exception e) { + System.out.println(); + System.out.println("Exception"); + System.out.println(e); + } + } +} \ No newline at end of file diff --git a/src/AuctionImpl.java b/src/AuctionImpl.java new file mode 100755 index 0000000..1896d28 --- /dev/null +++ b/src/AuctionImpl.java @@ -0,0 +1,389 @@ +/* + * AuctionProg 1.0 + * Copyright © 2016 Ben Goldsworthy (rumps) + * + * A program to facilitate a networked auction system. + * + * This file is part of AuctionProg. + * + * AuctionProg is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AuctionProg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AuctionProg. If not, see . + */ + +/** + ** This class provides the impementation for the AuctionServer. + **/ + +import java.io.*; +import java.util.*; +import java.security.*; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +/** + ** @author Ben Goldsworthy (rumps) + ** @version 1.0 + **/ +public class AuctionImpl extends java.rmi.server.UnicastRemoteObject implements Auction { + private ArrayList auctions; + private ArrayList users; + String status; + byte[] challenge = new byte[1024]; + + /** + ** Constructor Method. Required to declare the `RemoteException` + ** instance. + **/ + public AuctionImpl() throws java.rmi.RemoteException { + super(); + + System.out.println("Server initilising..."); + + auctions = new ArrayList(); + users = new ArrayList(); + status = ""; + generateKeys(); + + System.out.println("Server start successful."); + } + + private void generateKeys() { + try { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); + SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); + keyGen.initialize(1024, random); + + KeyPair pair = keyGen.generateKeyPair(); + writeKey(pair.getPublic()); + writeKey(pair.getPrivate()); + } catch (Exception e) { + System.out.println(); + System.out.println("Exception"); + System.out.println(e); + } + } + + /** + ** Creates an auction with the given details, generating a new ID for + ** it. + ** + ** @param desc The auction description. + ** @param owner The auction owner/creator. + ** @param startingPrice The auction starting price. + ** @param reserve The auction reserve price. + **/ + public void createAuction(String desc, UserWrapper owner, float startingPrice, float reserve) throws java.rmi.RemoteException { + int id = 0; + String preamble = "Create new auction: "; + + lines(); + System.out.println(preamble + "begin."); + + // Gives the new auction the lowest unclaimed ID. + for(AuctionWrapper item: auctions){ + if (id <= item.getID()) { + id = item.getID(); + } + } + + auctions.add(new AuctionWrapper(++id, desc, owner, startingPrice, reserve)); + System.out.println(preamble + "auction "+id+" successfully created."); + status = "Auction no. "+id+" successfully created."; + + System.out.println(preamble + "end."); + lines(); + } + + /** + ** Removes an auction, provided the user calling the method owns it. + ** If the reserve price was met, also returns the winning bidder. + ** + ** @param id The ID of the auction to remove. + ** @param currentUser The user calling the method. + ** @return The `UserWrapper` of the highest bidder, if applicable. + **/ + public UserWrapper removeAuction(int id, UserWrapper currentUser) throws java.rmi.RemoteException { + AuctionWrapper auction = this.getAuction(id); + UserWrapper response = null; + String preamble = "Close auction "+id+": "; + + lines(); + System.out.println(preamble + "begin."); + + if (auction.getOwner().getUsername().equals(currentUser.getUsername())) { + System.out.println(preamble + "ownership rights confirmed."); + auctions.remove(auction); + System.out.println(preamble + "auction successfully closed."); + status = "Auction no. "+id+" successfully removed"; + if (auction.getPrice() >= auction.getReserve()) { + System.out.println(preamble + "auction closed with winner."); + status = "Auction closed - winner"; + response = auction.getHighestBidder(); + } else { + System.out.println(preamble + "auction closed with no winner."); + status = "Auction closed - no winner"; + } + } else { + System.out.println(preamble + "invalid ownership rights."); + status = "Auction no. "+id+" could not be removed - you do not own this auction"; + } + + System.out.println(preamble + "end."); + lines(); + return response; + } + + /** + ** Bids on a given auction, provided the bid is more than the + ** current highest price. + ** + ** @param id The ID of the auction in question. + ** @param bidder The user bidding on the auction. + ** @param price The amount bid. + **/ + public void bidOnAuction(int id, UserWrapper bidder, float price) + throws java.rmi.RemoteException { + AuctionWrapper auction; + String preamble = "Bid on auction "+id+": "; + + lines(); + System.out.println(preamble + "begin."); + + if ((auction = this.getAuction(id)) != null) { + if (price > auction.getPrice()) { + this.getAuction(id).setBid(bidder, price); + System.out.println(preamble + "bid successful."); + status = "Bid successful"; + } else { + System.out.println(preamble + "bid less than current highest bid."); + status = "Price less than highest bid"; + } + } else { + System.out.println(preamble + "auction ID not found."); + status = "Invalid auction ID"; + } + + System.out.println(preamble + "end."); + lines(); + } + + /** + ** Accessor Method. Retrieves an auction by its ID. + ** + ** @param id The ID of the auction to retrieve. + ** @return The `AuctionWrapper` indicated. + **/ + private AuctionWrapper getAuction(int id) { + for(AuctionWrapper auction: auctions){ + if (auction.getID() == id) { + return auction; + } + } + return null; + } + + /** + ** Accessor Method. Retrieves a list of all the auctions. + ** + ** @return An `ArrayList` of `AuctionWrapper`s. + **/ + public ArrayList getAuctions() throws java.rmi.RemoteException { + return auctions; + } + + /** + ** Accessor Method. Gets a user, or creates a new one if non + ** exists with the given details. + ** + ** @param name The user's name. + ** @param email The user's email address. + ** @return The relevant `UserWrapper`. + **/ + public UserWrapper getUser(String username) throws java.rmi.RemoteException { + for(UserWrapper user: users){ + if (user.getUsername().equals(username)) { + status = "Welcome back, "+user.getName()+"."; + return user; + } + } + status = "No such user."; + return null; + } + + public UserWrapper registerUser(String name, String email, String username) throws java.rmi.RemoteException { + for(UserWrapper user: users){ + if (user.getUsername().equals(username)) { + status = "Username taken. Either choose a new username or, if trying to login to an existing account, rerun the program as 'AuctionClient '."; + return null; + } + } + + UserWrapper user = new UserWrapper(name, email, username); + users.add(user); + status = "New user created. Hello "+name+"."; + return user; + } + + /** + ** Accessor Method. Gets the status resulting from the last action + ** attempted. + ** + ** @return The status message. + **/ + public String getStatusofLast() { + return "\n"+status+"\n"; + } + + public PublicKey getPublicKey() throws java.rmi.RemoteException { + return this.readKey("server"); + } + + public void sendPublicKey(PublicKey key, String username) throws java.rmi.RemoteException { + this.writeKey(key, username); + } + + private static void writeKey(PrivateKey pKey) throws java.rmi.RemoteException { + try { + byte[] key = pKey.getEncoded(); + FileOutputStream keyfos = new FileOutputStream("../key/serverpriv.key"); + keyfos.write(key); + keyfos.close(); + } catch (Exception e) { + System.out.println(); + System.out.println("Exception"); + System.out.println(e); + } + } + + private static void writeKey(PublicKey pKey) throws java.rmi.RemoteException { + try { + byte[] key = pKey.getEncoded(); + FileOutputStream keyfos = new FileOutputStream("../key/serverpub.key"); + keyfos.write(key); + keyfos.close(); + } catch (Exception e) { + System.out.println(); + System.out.println("Exception"); + System.out.println(e); + } + } + + private static void writeKey(PublicKey pKey, String username) throws java.rmi.RemoteException { + try { + byte[] key = pKey.getEncoded(); + FileOutputStream keyfos = new FileOutputStream("../key/"+username+"pub.key"); + keyfos.write(key); + keyfos.close(); + } catch (Exception e) { + System.out.println(); + System.out.println("Exception"); + System.out.println(e); + } + } + + private static PrivateKey readKey() throws java.rmi.RemoteException { + try { + FileInputStream keyfis = new FileInputStream("../key/serverpriv.key"); + byte[] encKey = new byte[keyfis.available()]; + keyfis.read(encKey); + keyfis.close(); + + PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encKey); + + KeyFactory keyFactory = KeyFactory.getInstance("DSA"); + return keyFactory.generatePrivate(privKeySpec); + } catch (Exception e) { + System.out.println(); + System.out.println("Exception"); + System.out.println(e); + return null; + } + } + + private static PublicKey readKey(String username) throws java.rmi.RemoteException { + try { + FileInputStream keyfis = new FileInputStream("../key/"+username+"pub.key"); + byte[] encKey = new byte[keyfis.available()]; + keyfis.read(encKey); + + keyfis.close(); + + X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey); + + KeyFactory keyFactory = KeyFactory.getInstance("DSA"); + return keyFactory.generatePublic(pubKeySpec); + } catch (Exception e) { + System.out.println(); + System.out.println("Exception"); + System.out.println(e); + return null; + } + } + + + public byte[] challengeServer(byte[] challenge) throws java.rmi.RemoteException { + try { + Signature dsa = Signature.getInstance("SHA1withDSA"); + dsa.initSign(this.readKey()); + dsa.update(challenge); + byte[] realSig = dsa.sign(); + + return realSig; + } catch (Exception e) { + System.out.println(); + System.out.println("Exception"); + System.out.println(e); + return null; + } + } + + public byte[] getChallenge() throws java.rmi.RemoteException { + challenge = new byte[1024]; + new Random().nextBytes(this.challenge); + return this.challenge; + } + + public boolean returnChallenge(byte[] retChal, String username) throws java.rmi.RemoteException { + System.out.println("Authenticating user '"+username+"'..."); + for(UserWrapper user: users){ + if (user.getUsername().equals(username)) { + try { + Signature sig = Signature.getInstance("SHA1withDSA"); + sig.initVerify(this.readKey(username)); + + sig.update(this.challenge); + + boolean verifies = sig.verify(retChal); + System.out.println(username+" signature verifies: " + verifies); + return verifies; + } catch (Exception e) { + System.out.println(); + System.out.println("Exception"); + System.out.println(e); + } + } + } + System.out.println("User '"+username+"' not found."); + return false; + } + + public void close() throws java.rmi.RemoteException { + System.exit(-1); + } + + private void lines() { + for (int i = 0; i < 80; i++) System.out.print("-"); + System.out.print("\n"); + } +} + diff --git a/src/AuctionServer.java b/src/AuctionServer.java new file mode 100755 index 0000000..23edf4b --- /dev/null +++ b/src/AuctionServer.java @@ -0,0 +1,54 @@ +/* + * AuctionProg 1.0 + * Copyright © 2016 Ben Goldsworthy (rumps) + * + * A program to facilitate a networked auction system. + * + * This file is part of AuctionProg. + * + * AuctionProg is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AuctionProg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AuctionProg. If not, see . + */ + +/** + ** This class sets up the auction server using RMI. + **/ + +import java.rmi.Naming; + +/** + ** @author Ben Goldsworthy (rumps) + ** @version 1.0 + **/ +public class AuctionServer { + /** + ** Constructor Method. + **/ + public AuctionServer() { + try { + Auction a = new AuctionImpl(); + Naming.rebind("rmi://localhost/AuctionService", a); + } catch (Exception e) { + System.out.println("Server Error: " + e); + } + } + + /** + ** Runs the server. + ** + ** @param args Command-line arguments. + **/ + public static void main(String args[]) { + new AuctionServer(); + } +} diff --git a/src/AuctionWrapper.java b/src/AuctionWrapper.java new file mode 100755 index 0000000..0fa9816 --- /dev/null +++ b/src/AuctionWrapper.java @@ -0,0 +1,123 @@ +/* + * AuctionProg 1.0 + * Copyright © 2016 Ben Goldsworthy (rumps) + * + * A program to facilitate a networked auction system. + * + * This file is part of AuctionProg. + * + * AuctionProg is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AuctionProg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AuctionProg. If not, see . + */ + +/** + ** This class represents an Auction. + **/ + +import java.io.*; + +/** + ** @author Ben Goldsworthy (rumps) + ** @version 1.0 + **/ +public class AuctionWrapper implements Serializable { + private int id; + private String desc; + private UserWrapper owner; + private UserWrapper highestBidder; + private float price; + private float reserve; + + /** + ** Constructor Method. + ** @param id The ID of the auction. + ** @param desc The description of the auction. + ** @param owner The user creating the auction. + ** @param startingPrice The starting price of the auction. + ** @param reserve The reserve price of the auction. + **/ + public AuctionWrapper(int id, String desc, UserWrapper owner, float startingPrice, float reserve){ + this.id = id; + this.desc = desc; + this.owner = owner; + this.highestBidder = null; + this.price = startingPrice; + this.reserve = reserve; + } + + /** + ** Returns whether the auction has been sold on close. + ** @return Whether the auction has been sold or not. + **/ + public boolean isSold() { + return (this.price >= this.reserve) ? true : false; + } + + /** + ** Mutator Method. Sets the current highest bid. + ** @param bidder The user bidding. + ** @param price The bid price. + **/ + public void setBid(UserWrapper bidder, float price) { + this.highestBidder = bidder; + this.price = price; + } + + /** + ** Accessor Method. Gets the auction ID. + ** @return The auction ID. + **/ + public int getID() { + return this.id; + } + + /** + ** Accessor Method. Gets the auction description. + ** @return The auction description. + **/ + public String getDesc() { + return this.desc; + } + + /** + ** Accessor Method. Gets the auction owner. + ** @return The auction owner. + **/ + public UserWrapper getOwner() { + return this.owner; + } + + /** + ** Accessor Method. Gets the highest bidder on the auction. + ** @return The highest bidder on the auction. + **/ + public UserWrapper getHighestBidder() { + return this.highestBidder; + } + + /** + ** Accessor Method. Gets the current auction price. + ** @return The current auction price. + **/ + public float getPrice() { + return this.price; + } + + /** + ** Accessor Method. Gets the auction reserve price. + ** @return The auction reserve price. + **/ + public float getReserve() { + return this.reserve; + } +} diff --git a/src/GenSig.java b/src/GenSig.java new file mode 100755 index 0000000..e367f03 --- /dev/null +++ b/src/GenSig.java @@ -0,0 +1,47 @@ +import java.io.*; +import java.security.*; + +class GenSig { + public static void main(String[] args) { + /* Generate a DSA signature */ + + if (args.length != 1) { + System.out.println("Usage: GenSig nameOfFileToSign"); + } else try { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN"); + SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN"); + keyGen.initialize(1024, random); + + KeyPair pair = keyGen.generateKeyPair(); + PrivateKey priv = pair.getPrivate(); + PublicKey pub = pair.getPublic(); + + Signature dsa = Signature.getInstance("SHA1withDSA", "SUN"); + dsa.initSign(priv); + + FileInputStream fis = new FileInputStream(args[0]); + BufferedInputStream bufin = new BufferedInputStream(fis); + byte[] buffer = new byte[1024]; + int len; + while ((len = bufin.read(buffer)) >= 0) { + dsa.update(buffer, 0, len); + }; + bufin.close(); + + byte[] realSig = dsa.sign(); + + /* save the signature in a file */ + FileOutputStream sigfos = new FileOutputStream("sig"); + sigfos.write(realSig); + sigfos.close(); + + /* save the public key in a file */ + byte[] key = pub.getEncoded(); + FileOutputStream keyfos = new FileOutputStream("suepk"); + keyfos.write(key); + keyfos.close(); + } catch (Exception e) { + System.err.println("Caught exception " + e.toString()); + } + } +} \ No newline at end of file diff --git a/src/UserWrapper.java b/src/UserWrapper.java new file mode 100755 index 0000000..495cf1f --- /dev/null +++ b/src/UserWrapper.java @@ -0,0 +1,69 @@ +/* + * AuctionProg 1.0 + * Copyright © 2016 Ben Goldsworthy (rumps) + * + * A program to facilitate a networked auction system. + * + * This file is part of AuctionProg. + * + * AuctionProg is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AuctionProg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AuctionProg. If not, see . + */ + +/** + ** This class represents a User. + **/ + +import java.io.*; + +/** + ** @author Ben Goldsworthy (rumps) + ** @version 1.0 + **/ +public class UserWrapper implements Serializable { + private String name; + private String email; + private String username; + + /** + ** Constructor Method. + ** @param id The ID of the user. + ** @param name The user's name. + ** @param email The user's email address. + **/ + public UserWrapper(String name, String email, String username){ + this.name = name; + this.email = email; + this.username = username; + } + + /** + ** Accessor Method. Returns the user's name. + ** @param The user's name. + **/ + public String getName() { + return this.name; + } + + public String getUsername() { + return this.username; + } + + /** + ** Accessor Method. Returns the user's email address. + ** @param The user's email address. + **/ + public String getEmail() { + return this.email; + } +}