· 8 years ago · Jan 14, 2018, 03:14 PM
1import java.io.BufferedReader;
2import java.io.Console;
3import java.io.DataOutputStream;
4import java.io.File;
5import java.io.FileOutputStream;
6import java.io.IOException;
7import java.io.InputStreamReader;
8import java.nio.ByteBuffer;
9import java.nio.CharBuffer;
10import java.nio.charset.Charset;
11import java.nio.charset.CharsetEncoder;
12import java.security.InvalidAlgorithmParameterException;
13import java.security.InvalidKeyException;
14import java.security.NoSuchAlgorithmException;
15import java.security.spec.InvalidKeySpecException;
16import java.util.Arrays;
17import java.util.Random;
18
19import javax.crypto.Cipher;
20import javax.crypto.CipherOutputStream;
21import javax.crypto.NoSuchPaddingException;
22import javax.crypto.SecretKey;
23import javax.crypto.SecretKeyFactory;
24import javax.crypto.spec.PBEKeySpec;
25import javax.crypto.spec.PBEParameterSpec;
26
27public class MinecraftLoginEncrypter {
28 public static void main(String[] args) throws IOException {
29 System.err.println("Security Note: Please check that this program has not been modified to harvest your login before inputting your username-password combination. In the source, look for \"java.net\"; in the binary, look for \"Ljava/net\" in a hex editor.");
30 BufferedReader keyboardLines = new BufferedReader(new InputStreamReader(System.in));
31 System.err.print("Username: ");
32 String user = keyboardLines.readLine();
33 char[] pass = null;
34 try {
35 Console console = System.console();
36 if (console != null) {
37 System.err.print("Password: ");
38 pass = console.readPassword();
39 }
40 } catch (NoClassDefFoundError ncdfe) {
41 // pass = null;
42 } catch (NoSuchMethodError nsme) {
43 // pass = null;
44 }
45 if (pass == null) {
46 System.err.println("Security Note: No password-hiding functionality is available in this Java VM. The following password prompt will SHOW the password you enter.");
47 System.err.print("Password: ");
48 pass = keyboardLines.readLine().toCharArray();
49 }
50 MinecraftLoginEncrypter encrypter = new MinecraftLoginEncrypter(user, pass);
51 try {
52 encrypter.writeFile(new File(".", "lastlogin"));
53 System.err.println("File written.");
54 } finally {
55 encrypter.close();
56 }
57 }
58
59 private final String user;
60
61 private final char[] pass;
62
63 public MinecraftLoginEncrypter(final String user, final char[] pass) {
64 this.user = user;
65 this.pass = pass;
66 }
67
68 public void writeFile(File file) throws IOException {
69 Cipher cipher;
70 try {
71 cipher = getCipher(Cipher.ENCRYPT_MODE, "passwordfile");
72 } catch (Exception e) {
73 throw new IOException("Error occurred while creating the cipher for the Minecraft login file", e);
74 }
75 DataOutputStream dos;
76 if (cipher != null)
77 dos = new DataOutputStream(new CipherOutputStream(new FileOutputStream(file), cipher));
78 else {
79 dos = new DataOutputStream(new FileOutputStream(file));
80 }
81 dos.writeUTF(user);
82 CharsetEncoder c = Charset.forName("UTF-8").newEncoder();
83 ByteBuffer bb = ByteBuffer.allocate(pass.length * (int) Math.ceil(c.maxBytesPerChar()));
84 try {
85 c.encode(CharBuffer.wrap(pass), bb, true);
86 c.reset();
87 dos.writeShort(bb.position());
88 bb.flip();
89 byte[] passBytes = new byte[bb.remaining()];
90 try {
91 bb.get(passBytes);
92 dos.write(passBytes);
93 } finally {
94 // Avoid memory sniffing attacks: zero out the password
95 Arrays.fill(passBytes, (byte) 0);
96 }
97 } finally {
98 bb.clear();
99 // Avoid memory sniffing attacks: zero out the password
100 for (int i = 0; i < bb.limit(); i++) {
101 bb.put(i, (byte) 0);
102 }
103 }
104 dos.flush();
105 dos.close();
106 }
107
108 public void close() {
109 // Avoid memory sniffing attacks: zero out the password
110 Arrays.fill(pass, '\0');
111 }
112
113 protected void finalize() throws Throwable {
114 close();
115 }
116
117 private Cipher getCipher(int mode, String password) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
118 Random random = new Random(43287234L);
119 byte[] salt = new byte[8];
120 random.nextBytes(salt);
121 PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 5);
122
123 SecretKey pbeKey = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(new PBEKeySpec(password.toCharArray()));
124 Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
125 cipher.init(mode, pbeKey, pbeParamSpec);
126 return cipher;
127 }
128}