Skip to content

Commit 35527f9

Browse files
committed
Make Crypto functions aware of secure_string.
Also fixed a bug in secure_string where the decrypted char array was the wrong size due to padding.
1 parent 550706d commit 35527f9

4 files changed

Lines changed: 77 additions & 27 deletions

File tree

src/main/java/com/laytonsmith/PureUtilities/Common/Annotations/AnnotationChecks.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
import java.util.HashSet;
2020
import java.util.List;
2121
import java.util.Set;
22-
import java.util.logging.Level;
23-
import java.util.logging.Logger;
2422

2523
/**
2624
* This class is run by maven at compile time, and checks to ensure that the various annotations referenced here are

src/main/java/com/laytonsmith/core/MainSandbox.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,30 @@
77
*/
88
public class MainSandbox {
99

10-
public static interface B1 {
11-
String method(int i, String b);
10+
public static interface Interface {
11+
void method(int i, String b, int j);
1212
}
13-
@NonInheritImplements(B1.class)
13+
@NonInheritImplements(Interface.class)
1414
public static class A1 {
15-
public String method(int i, String b) {
16-
return "";
15+
public void method(int i, String b, int j) {
16+
System.out.println("i: " + i + "; b: " + b);
1717
}
1818
}
19+
20+
public static class A2 extends A1 {
21+
void moreMethods() {
22+
23+
}
24+
}
25+
1926
public static void main(String[] argv) throws Exception {
27+
Interface i_f = NonInheritImplements.Helper.Cast(Interface.class, new A1());
28+
System.out.println(NonInheritImplements.Helper.Instanceof(new A2(), Interface.class));
29+
myMethod(i_f);
30+
}
2031

32+
public static void myMethod(Interface iface) {
33+
iface.method(12, "string", 123);
2134
}
2235

2336
}

src/main/java/com/laytonsmith/core/constructs/CSecureString.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public class CSecureString extends CString {
3737
private byte[] encrypted;
3838
private Cipher decrypter;
3939
private int encLength;
40+
private int actualLength;
4041

4142
public CSecureString(char[] val, Target t) {
4243
super("**secure string**", t);
@@ -50,6 +51,7 @@ public CSecureString(CArray val, Target t) {
5051

5152
private void construct(byte[] val) {
5253
try {
54+
actualLength = val.length;
5355
SecureRandom rand = SecureRandom.getInstanceStrong();
5456
byte[] keyBytes = new byte[24];
5557
rand.nextBytes(keyBytes);
@@ -93,6 +95,7 @@ public char[] getDecryptedCharArray() {
9395
byte[] decrypted = new byte[decrypter.getOutputSize(encLength)];
9496
int decLen = decrypter.update(encrypted, 0, encLength, decrypted, 0);
9597
decrypter.doFinal(decrypted, decLen);
98+
decrypted = ArrayUtils.slice(decrypted, 0, actualLength - 1);
9699
return ArrayUtils.bytesToChar(decrypted);
97100
} catch(ShortBufferException | IllegalBlockSizeException | BadPaddingException ex) {
98101
throw new RuntimeException(ex);
@@ -103,9 +106,6 @@ public CArray getDecryptedCharCArray() {
103106
char[] array = getDecryptedCharArray();
104107
CArray carray = new CArray(Target.UNKNOWN, array.length);
105108
for(char c : array) {
106-
if(c == '\0') {
107-
continue;
108-
}
109109
carray.push(new CString(c, Target.UNKNOWN), Target.UNKNOWN);
110110
}
111111
return carray;

src/main/java/com/laytonsmith/core/functions/Crypto.java

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.laytonsmith.core.functions;
22

3+
import com.laytonsmith.PureUtilities.Common.ArrayUtils;
34
import com.laytonsmith.PureUtilities.Common.StringUtils;
45
import com.laytonsmith.PureUtilities.Version;
56
import com.laytonsmith.annotations.api;
@@ -9,6 +10,7 @@
910
import com.laytonsmith.core.Static;
1011
import com.laytonsmith.core.constructs.CBoolean;
1112
import com.laytonsmith.core.constructs.CByteArray;
13+
import com.laytonsmith.core.constructs.CSecureString;
1214
import com.laytonsmith.core.constructs.CString;
1315
import com.laytonsmith.core.constructs.Construct;
1416
import com.laytonsmith.core.constructs.Target;
@@ -36,22 +38,35 @@
3638
public class Crypto {
3739

3840
public static String docs() {
39-
return "Provides common cryptographic functions";
41+
return "Provides common cryptographic functions. Many functions in this class are aware of and compatible"
42+
+ " with secure_string (where specified in the function documentation). In these cases, if the"
43+
+ " argument passed in is a secure_string, it is first decrypted and the underlying string is used"
44+
+ " rather than the default string value \"**secure string**\".";
4045
}
4146

4247
private static CString getHMAC(String algorithm, Target t, Construct[] args) {
4348
try {
4449
SecretKeySpec signingKey = new SecretKeySpec(args[0].val().getBytes(), algorithm);
4550
Mac mac = Mac.getInstance(algorithm);
4651
mac.init(signingKey);
47-
byte[] hmac = mac.doFinal(args[1].val().getBytes());
52+
byte[] hmac = mac.doFinal(getByteArrayFromArg(args[1]));
4853
String hash = StringUtils.toHex(hmac).toLowerCase();
4954
return new CString(hash, t);
5055
} catch(NoSuchAlgorithmException | InvalidKeyException ex) {
5156
throw new CREPluginInternalException("An error occured while trying to hash your data", t, ex);
5257
}
5358
}
5459

60+
private static byte[] getByteArrayFromArg(Construct c) {
61+
byte[] val;
62+
if(c instanceof CSecureString) {
63+
val = ArrayUtils.charToBytes(((CSecureString)c).getDecryptedCharArray());
64+
} else {
65+
val = c.val().getBytes();
66+
}
67+
return val;
68+
}
69+
5570
@api
5671
public static class rot13 extends AbstractFunction implements Optimizable {
5772

@@ -144,7 +159,7 @@ public Integer[] numArgs() {
144159
public String docs() {
145160
return "string {val} Returns the md5 hash of the specified string. The md5 hash is no longer considered secure, so you should"
146161
+ " not use it for storage of sensitive data, however for general hashing, it is a quick and easy solution. md5 is"
147-
+ " a one way hashing algorithm.";
162+
+ " a one way hashing algorithm. This function is aware of and compatible with secure_string.";
148163
}
149164

150165
@Override
@@ -170,8 +185,9 @@ public Boolean runAsync() {
170185
@Override
171186
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
172187
try {
188+
byte[] val = getByteArrayFromArg(args[0]);
173189
MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
174-
digest.update(args[0].val().getBytes());
190+
digest.update(val);
175191
String hash = StringUtils.toHex(digest.digest()).toLowerCase();
176192
return new CString(hash, t);
177193
} catch(NoSuchAlgorithmException ex) {
@@ -212,7 +228,8 @@ public Integer[] numArgs() {
212228
public String docs() {
213229
return "string {val} Returns the sha1 hash of the specified string. Note that sha1 is considered more secure than md5,"
214230
+ " but is also not considered secure. sha-256 should be used instead for storing sensitive"
215-
+ " data. It is a one way hashing algorithm.";
231+
+ " data. It is a one way hashing algorithm. This function is aware of and compatible with"
232+
+ " secure_string.";
216233
}
217234

218235
@Override
@@ -238,8 +255,9 @@ public Boolean runAsync() {
238255
@Override
239256
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
240257
try {
258+
byte[] val = getByteArrayFromArg(args[0]);
241259
MessageDigest digest = java.security.MessageDigest.getInstance("SHA1");
242-
digest.update(args[0].val().getBytes());
260+
digest.update(val);
243261
String hash = StringUtils.toHex(digest.digest()).toLowerCase();
244262
return new CString(hash, t);
245263
} catch(NoSuchAlgorithmException ex) {
@@ -279,7 +297,8 @@ public Integer[] numArgs() {
279297
@Override
280298
public String docs() {
281299
return "string {val} Returns the sha256 hash of the specified string. Note that sha256 is considered more secure than sha1 and md5, and is"
282-
+ " typically used when storing sensitive data. It is a one way hashing algorithm.";
300+
+ " typically used when storing sensitive data. It is a one way hashing algorithm. This function"
301+
+ " is aware of and compatible with secure_string.";
283302
}
284303

285304
@Override
@@ -305,8 +324,9 @@ public Boolean runAsync() {
305324
@Override
306325
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
307326
try {
327+
byte[] val = getByteArrayFromArg(args[0]);
308328
MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256");
309-
digest.update(args[0].val().getBytes());
329+
digest.update(val);
310330
String hash = StringUtils.toHex(digest.digest()).toLowerCase();
311331
return new CString(hash, t);
312332
} catch(NoSuchAlgorithmException ex) {
@@ -348,7 +368,8 @@ public Integer[] numArgs() {
348368
public String docs() {
349369
return "string {val} Returns the sha512 hash of the specified string. Note that sha512"
350370
+ " is considered more secure than sha1 and md5 (and sha256, because it takes longer to calculate),"
351-
+ " and is typically used when storing sensitive data. It is a one way hashing algorithm.";
371+
+ " and is typically used when storing sensitive data. It is a one way hashing algorithm. This"
372+
+ " function is aware of and compatible with secure_string.";
352373
}
353374

354375
@Override
@@ -374,8 +395,9 @@ public Boolean runAsync() {
374395
@Override
375396
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
376397
try {
398+
byte[] val = getByteArrayFromArg(args[0]);
377399
MessageDigest digest = java.security.MessageDigest.getInstance("SHA-512");
378-
digest.update(args[0].val().getBytes());
400+
digest.update(val);
379401
String hash = StringUtils.toHex(digest.digest()).toLowerCase();
380402
return new CString(hash, t);
381403
} catch(NoSuchAlgorithmException ex) {
@@ -425,7 +447,13 @@ public Construct exec(Target t, Environment environment, Construct... args) thro
425447
log_rounds = Static.getInt32(args[1], t);
426448
}
427449
try {
428-
String hash = BCrypt.hashpw(args[0].val(), BCrypt.gensalt(log_rounds));
450+
String val;
451+
if(args[0] instanceof CSecureString) {
452+
val = new String(((CSecureString)args[0]).getDecryptedCharArray());
453+
} else {
454+
val = args[0].val();
455+
}
456+
String hash = BCrypt.hashpw(val, BCrypt.gensalt(log_rounds));
429457
return new CString(hash, t);
430458
} catch(IllegalArgumentException ex) {
431459
throw new CRERangeException(ex.getMessage(), t);
@@ -452,7 +480,8 @@ public String docs() {
452480
+ " complete in under a second, however, setting it to 10 will take"
453481
+ " many seconds, and setting it to 15 will take a few minutes. The workload must be between 5"
454482
+ " and 31. See the documentation for check_bcrypt for full usage. Bcrypt is recommended for"
455-
+ " password hashing, whereas sha-* functions are not.";
483+
+ " password hashing, whereas sha-* functions are not. This function is aware of and compatible"
484+
+ " with secure_string.";
456485
}
457486

458487
@Override
@@ -489,7 +518,13 @@ public Boolean runAsync() {
489518

490519
@Override
491520
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
492-
return CBoolean.get(BCrypt.checkpw(args[0].val(), args[1].val()));
521+
String val;
522+
if(args[0] instanceof CSecureString) {
523+
val = new String(((CSecureString)args[0]).getDecryptedCharArray());
524+
} else {
525+
val = args[0].val();
526+
}
527+
return CBoolean.get(BCrypt.checkpw(val, args[1].val()));
493528
}
494529

495530
@Override
@@ -510,7 +545,8 @@ public String docs() {
510545
+ "string @plain = 'plaintext';\n"
511546
+ "string @hash = bcrypt(@plain);\n"
512547
+ "msg(if(check_bcrypt(@plain, @hash),"
513-
+ " 'They match!', 'They do not match!'));\n";
548+
+ " 'They match!', 'They do not match!'));\n"
549+
+ "\n\nThis function is aware of and compatible with secure_string.";
514550
}
515551

516552
@Override
@@ -653,7 +689,8 @@ public Integer[] numArgs() {
653689

654690
@Override
655691
public String docs() {
656-
return "string {key, val} Returns the md5 HMAC of the specified string using the provided key.";
692+
return "string {key, val} Returns the md5 HMAC of the specified string using the provided key. This function"
693+
+ " is aware of and compatible with secure_string.";
657694
}
658695

659696
@Override
@@ -711,7 +748,8 @@ public Integer[] numArgs() {
711748

712749
@Override
713750
public String docs() {
714-
return "string {key, val} Returns the sha1 HMAC of the specified string using the provided key.";
751+
return "string {key, val} Returns the sha1 HMAC of the specified string using the provided key. This function"
752+
+ " is aware of and compatible with secure_string.";
715753
}
716754

717755
@Override
@@ -769,7 +807,8 @@ public Integer[] numArgs() {
769807

770808
@Override
771809
public String docs() {
772-
return "string {key, val} Returns the sha256 HMAC of the specified string using the provided key.";
810+
return "string {key, val} Returns the sha256 HMAC of the specified string using the provided key. This"
811+
+ " function is aware of and compatible with secure_string.";
773812
}
774813

775814
@Override

0 commit comments

Comments
 (0)