mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-08 07:05:06 +00:00
Check / Set passwords for password tags
This commit is contained in:
@@ -19,10 +19,13 @@ package com.jpexs.decompiler.flash.tags;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.PasswordTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Password;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Reserved;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.MD5Crypt;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@@ -30,7 +33,7 @@ import java.io.IOException;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class EnableDebugger2Tag extends Tag {
|
||||
public class EnableDebugger2Tag extends Tag implements PasswordTag {
|
||||
|
||||
public static final int ID = 64;
|
||||
|
||||
@@ -43,6 +46,7 @@ public class EnableDebugger2Tag extends Tag {
|
||||
/**
|
||||
* MD5 hash of password
|
||||
*/
|
||||
@Password
|
||||
public String passwordHash;
|
||||
|
||||
/**
|
||||
@@ -52,7 +56,7 @@ public class EnableDebugger2Tag extends Tag {
|
||||
*/
|
||||
public EnableDebugger2Tag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
passwordHash = "PasswordHash";
|
||||
setPassword("");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,4 +88,14 @@ public class EnableDebugger2Tag extends Tag {
|
||||
sos.writeUI16(reserved);
|
||||
sos.writeString(passwordHash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPassword(String password) {
|
||||
this.passwordHash = MD5Crypt.crypt(password, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPassword(String password) {
|
||||
return this.passwordHash.equals(MD5Crypt.crypt(password, 2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,10 @@ package com.jpexs.decompiler.flash.tags;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.PasswordTag;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Password;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.MD5Crypt;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@@ -27,7 +30,7 @@ import java.io.IOException;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class EnableDebuggerTag extends Tag {
|
||||
public class EnableDebuggerTag extends Tag implements PasswordTag {
|
||||
|
||||
public static final int ID = 58;
|
||||
|
||||
@@ -36,6 +39,7 @@ public class EnableDebuggerTag extends Tag {
|
||||
/**
|
||||
* MD5 hash of password
|
||||
*/
|
||||
@Password
|
||||
public String passwordHash;
|
||||
|
||||
/**
|
||||
@@ -45,7 +49,7 @@ public class EnableDebuggerTag extends Tag {
|
||||
*/
|
||||
public EnableDebuggerTag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
passwordHash = "PasswordHash";
|
||||
setPassword("");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,4 +81,16 @@ public class EnableDebuggerTag extends Tag {
|
||||
sos.writeString(passwordHash);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPassword(String password) {
|
||||
//Assuming EnableDebugger tag has same hash type as EnableDebugger2
|
||||
this.passwordHash = MD5Crypt.crypt(password, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPassword(String password) {
|
||||
return this.passwordHash.equals(MD5Crypt.crypt(password, 2));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,10 @@ package com.jpexs.decompiler.flash.tags;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.PasswordTag;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Password;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.MD5Crypt;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@@ -27,7 +30,7 @@ import java.io.IOException;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ProtectTag extends Tag {
|
||||
public class ProtectTag extends Tag implements PasswordTag {
|
||||
|
||||
public static final int ID = 24;
|
||||
|
||||
@@ -36,6 +39,7 @@ public class ProtectTag extends Tag {
|
||||
/**
|
||||
* MD5 hash of password
|
||||
*/
|
||||
@Password
|
||||
public String passwordHash;
|
||||
|
||||
/**
|
||||
@@ -81,4 +85,16 @@ public class ProtectTag extends Tag {
|
||||
sos.writeString(passwordHash);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPassword(String password) {
|
||||
//Assuming Protect tag has same hash type as EnableDebugger2
|
||||
this.passwordHash = MD5Crypt.crypt(password, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPassword(String password) {
|
||||
return this.passwordHash.equals(MD5Crypt.crypt(password, 2));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface PasswordTag {
|
||||
|
||||
public void setPassword(String password);
|
||||
|
||||
public boolean hasPassword(String password);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. */
|
||||
package com.jpexs.decompiler.flash.types.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Password field - it has MD5 crypted password.
|
||||
*
|
||||
* TODO: use this in GUI tag editor to set passwords
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Password {
|
||||
}
|
||||
246
libsrc/ffdec_lib/src/com/jpexs/helpers/MD5Crypt.java
Normal file
246
libsrc/ffdec_lib/src/com/jpexs/helpers/MD5Crypt.java
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.helpers;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* MD5 crypt - based on passlib.hash.md5_crypt
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class MD5Crypt {
|
||||
|
||||
private static final String SALT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
|
||||
private static final String HASH64_CHARS = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
public static final String MAGIC = "$1$";
|
||||
public static final String MAGIC_APACHE = "$apr1$";
|
||||
|
||||
public static boolean checkPassword(String password, String hash) {
|
||||
String magic;
|
||||
|
||||
if (hash.startsWith(MAGIC)) {
|
||||
magic = MAGIC;
|
||||
} else if (hash.startsWith(MAGIC_APACHE)) {
|
||||
magic = MAGIC_APACHE;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
String checksum = hash.substring(magic.length());
|
||||
String salt = "";
|
||||
if (checksum.contains("$")) {
|
||||
salt = checksum.substring(0, checksum.indexOf("$"));
|
||||
}
|
||||
return hash.equals(crypt(password, salt, magic));
|
||||
}
|
||||
|
||||
public static String generateSalt(int length) {
|
||||
Random rnd = new Random();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < length; i++) {
|
||||
sb.append(SALT_CHARS.charAt(rnd.nextInt(SALT_CHARS.length())));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String crypt(String password, int saltLength, String magic) {
|
||||
return crypt(password, generateSalt(saltLength), magic);
|
||||
}
|
||||
|
||||
public static String crypt(String password, int saltLength) {
|
||||
return crypt(password, generateSalt(saltLength), MAGIC);
|
||||
}
|
||||
|
||||
public static String cryptApache(String password, int saltLength) {
|
||||
return crypt(password, generateSalt(saltLength), MAGIC_APACHE);
|
||||
}
|
||||
|
||||
public static String crypt(String password, String salt) {
|
||||
return crypt(password, salt, MAGIC);
|
||||
}
|
||||
|
||||
public static String cryptApache(String password, String salt) {
|
||||
return crypt(password, salt, MAGIC_APACHE);
|
||||
}
|
||||
|
||||
private static String crypt(String password, String salt, String magic) {
|
||||
|
||||
if (salt.startsWith(magic)) {
|
||||
salt = salt.substring(magic.length());
|
||||
}
|
||||
if (salt.length() > 8) {
|
||||
salt = salt.substring(0, 8);
|
||||
}
|
||||
|
||||
byte[] passwordBytes = new byte[0];
|
||||
byte[] constBytes = new byte[0];
|
||||
byte[] saltBytes = new byte[0];
|
||||
try {
|
||||
passwordBytes = password.getBytes("UTF-8");
|
||||
saltBytes = salt.getBytes("UTF-8");
|
||||
constBytes = magic.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
//ignore
|
||||
}
|
||||
|
||||
MessageDigest b;
|
||||
try {
|
||||
b = MessageDigest.getInstance("MD5"); //Start MD5 digest B
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
return null;
|
||||
}
|
||||
b.update(passwordBytes); //Add the password to digest B
|
||||
b.update(saltBytes);//Add the salt to digest B
|
||||
b.update(passwordBytes); //Add the password to digest B
|
||||
byte[] digest_b = b.digest(); //Finish MD5 digest B
|
||||
|
||||
MessageDigest a;
|
||||
try {
|
||||
a = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
return null;
|
||||
}
|
||||
a.update(passwordBytes); //Add the password to digest A
|
||||
a.update(constBytes); //Add the constant string $1$ to digest A
|
||||
a.update(saltBytes); //Add the salt to digest A
|
||||
|
||||
//For each block of 16 bytes in the password string, add digest B to digest A
|
||||
for (int i = passwordBytes.length; i > 0; i -= 16) {
|
||||
if (i >= 16) {
|
||||
a.update(digest_b);
|
||||
} else { //For the remaining N bytes of the password string, add the first N bytes of digest B to digest A
|
||||
a.update(digest_b, 0, i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
For each bit in the binary representation of the length of the password string; starting with the lowest value bit, up to and including the largest-valued bit that is set to 1:
|
||||
|
||||
If the current bit is set 0 (!! not 1), add the first character of the password to digest A.
|
||||
Otherwise, add a NULL character to digest A.
|
||||
|
||||
(If the password is the empty string, step 14 is omitted entirely).
|
||||
*/
|
||||
for (int i = passwordBytes.length; i > 0; i = i >>> 1) {
|
||||
if ((i & 1) == 0) {
|
||||
a.update(passwordBytes, 0, 1);
|
||||
} else {
|
||||
a.update((byte) 0);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] digest_a = a.digest(); //Finish MD5 digest A
|
||||
byte[] round_result = null;
|
||||
|
||||
//For 1000 rounds (round values 0..999 inclusive)
|
||||
for (int round = 0; round < 1000; round++) {
|
||||
MessageDigest c;
|
||||
try {
|
||||
c = MessageDigest.getInstance("MD5"); //Start MD5 digest C
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//If the round is odd, add the password to digest C
|
||||
if (round % 2 == 1) {
|
||||
c.update(passwordBytes);
|
||||
}
|
||||
|
||||
//If the round is even, add the previous round’s result to digest C (for round 0, add digest A instead).
|
||||
if (round % 2 == 0) {
|
||||
if (round == 0) {
|
||||
c.update(digest_a);
|
||||
} else {
|
||||
c.update(round_result);
|
||||
}
|
||||
}
|
||||
//If the round is not a multiple of 3, add the salt to digest C.
|
||||
if (round % 3 != 0) {
|
||||
c.update(saltBytes);
|
||||
}
|
||||
|
||||
//If the round is not a multiple of 7, add the password to digest C.
|
||||
if (round % 7 != 0) {
|
||||
c.update(passwordBytes);
|
||||
}
|
||||
|
||||
//If the round is even, add the password to digest C.
|
||||
if (round % 2 == 0) {
|
||||
c.update(passwordBytes);
|
||||
}
|
||||
|
||||
//If the round is odd, add the previous round’s result to digest C (for round 0, add digest A instead).
|
||||
if (round % 2 == 1) {
|
||||
if (round == 0) {
|
||||
c.update(digest_a);
|
||||
} else {
|
||||
c.update(round_result);
|
||||
}
|
||||
}
|
||||
|
||||
//Use the final value of MD5 digest C as the result for this round.
|
||||
round_result = c.digest();
|
||||
}
|
||||
|
||||
//Transpose the 16 bytes of the final round’s result in the following order:
|
||||
//12,6,0,13,7,1,14,8,2,15,9,3,5,10,4,11
|
||||
byte[] transposed = new byte[]{
|
||||
round_result[12],
|
||||
round_result[6],
|
||||
round_result[0],
|
||||
round_result[13],
|
||||
round_result[7],
|
||||
round_result[1],
|
||||
round_result[14],
|
||||
round_result[8],
|
||||
round_result[2],
|
||||
round_result[15],
|
||||
round_result[9],
|
||||
round_result[3],
|
||||
round_result[5],
|
||||
round_result[10],
|
||||
round_result[4],
|
||||
round_result[11]};
|
||||
|
||||
//Encode the resulting 16 byte string into a 22 character hash64-encoded string
|
||||
//(the 2 msb bits encoded by the last hash64 character are used as 0 padding).
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
int dstCharRem = 22;
|
||||
for (int srcBytePos = 0; srcBytePos < transposed.length; srcBytePos += 3, dstCharRem -= 4) {
|
||||
long v = (transposed[srcBytePos] & 0xff);
|
||||
if (srcBytePos + 1 < transposed.length) {
|
||||
v |= ((transposed[srcBytePos + 1] & 0xff) << 8);
|
||||
}
|
||||
if (srcBytePos + 2 < transposed.length) {
|
||||
v |= ((transposed[srcBytePos + 2] & 0xff) << 16);
|
||||
}
|
||||
for (int j = 0; j < (dstCharRem >= 4 ? 4 : dstCharRem); j++) {
|
||||
result.append(HASH64_CHARS.charAt((int) (v & 0x3f)));
|
||||
v >>>= 6;
|
||||
}
|
||||
}
|
||||
return magic + salt + "$" + result.toString();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user