[m-rev.] for post-commit review: fix system RNG hanldes in the C# and Java grades
Julien Fischer
jfischer at opturion.com
Fri Feb 19 23:19:19 AEDT 2021
Fix system RNG handles in the C# and Java grades.
Ensure it is not possible to use a system RNG handle after it has been closed
in the C# and Java grades. This brings the implementation for these backends
into line with the /dev/urandom implementation on C. (The other C implementation
will be made to conform in a separate change.)
library/random.system_rng.m:
Add wrapper classes around the C# and Java system RNGs that allow
us to track if they have already been closed.
Julien.
diff --git a/library/random.system_rng.m b/library/random.system_rng.m
index a8d0843..7e7339f 100644
--- a/library/random.system_rng.m
+++ b/library/random.system_rng.m
@@ -203,7 +203,6 @@ extern ML_SystemRandomHandle ML_random_open(MR_Bool *succeeded,
//
extern MR_Bool ML_random_close(ML_SystemRandomHandle handle, MR_String *err_msg);
-
// Fill buffer with len random bytes generated by the system RNG.
// Returns MR_TRUE if len bytes were generated; err_msg will point to the empty
// string.
@@ -215,12 +214,112 @@ extern MR_Bool ML_random_generate_bytes(ML_SystemRandomHandle handle,
unsigned char *buffer, size_t len, MR_String *err_msg);
").
+:- pragma foreign_code("C#", "
+
+ public class ML_SystemRandomHandle {
+
+ private System.Security.Cryptography.RandomNumberGenerator handle;
+
+ public ML_SystemRandomHandle() {
+ handle =
+ System.Security.Cryptography.RandomNumberGenerator.Create();
+ }
+
+ public void close() {
+ handle = null;
+ }
+
+ public bool isClosed() {
+ return (handle == null);
+ }
+
+ public byte getByte() {
+ byte[] bytes = new byte[1];
+ handle.GetBytes(bytes);
+ return bytes[0];
+ }
+
+ public ushort getUShort() {
+ byte[] bytes = new byte[2];
+ handle.GetBytes(bytes);
+ return (ushort) (bytes[1] << 8 | (bytes[0] & 0x00ff));
+ }
+
+ public uint getUInt() {
+ byte[] bytes = new byte[4];
+ handle.GetBytes(bytes);
+ return (uint) (
+ bytes[3] << 24 |
+ bytes[2] << 16 |
+ bytes[1] << 8 |
+ bytes[0]);
+ }
+
+ public ulong getULong() {
+ byte[] bytes = new byte[8];
+ handle.GetBytes(bytes);
+ return (ulong) (
+ (ulong) bytes[7] << 56 |
+ (ulong) bytes[6] << 48 |
+ (ulong) bytes[5] << 40 |
+ (ulong) bytes[4] << 32 |
+ (ulong) bytes[3] << 24 |
+ (ulong) bytes[2] << 16 |
+ (ulong) bytes[1] << 8 |
+ (ulong) bytes[0]);
+ }
+ }
+").
+
+:- pragma foreign_code("Java", "
+
+ public static class ML_SystemRandomHandle {
+
+ private java.security.SecureRandom handle;
+
+ public ML_SystemRandomHandle() {
+ handle = new java.security.SecureRandom();
+ }
+
+ public void close() {
+ handle = null;
+ }
+
+ public boolean isClosed() {
+ return (handle == null);
+ }
+
+ public byte getByte() {
+ byte[] bytes = new byte[1];
+ handle.nextBytes(bytes);
+ return bytes[0];
+ }
+
+ public short getShort() {
+ byte[] bytes = new byte[2];
+ handle.nextBytes(bytes);
+ return (short)
+ (bytes[0] << java.lang.Byte.SIZE | (bytes[1] & 0x00ff));
+ }
+
+ public int getInt() {
+ return handle.nextInt();
+ }
+
+ public long getLong() {
+ return handle.nextLong();
+ }
+ }
+").
+
+%---------------------------------------------------------------------------%
+
:- pragma foreign_type("C", system_rng,
"ML_SystemRandomHandle", [can_pass_as_mercury_type]).
:- pragma foreign_type("C#", system_rng,
- "System.Security.Cryptography.RandomNumberGenerator").
+ "random__system_rng.ML_SystemRandomHandle").
:- pragma foreign_type("Java", system_rng,
- "java.security.SecureRandom").
+ "random__system_rng.ML_SystemRandomHandle").
%---------------------------------------------------------------------------%
@@ -294,8 +393,7 @@ open_system_rng(Result, !IO) :-
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe],
"
- Handle =
- System.Security.Cryptography.RandomNumberGenerator.Create();
+ Handle = new random__system_rng.ML_SystemRandomHandle();
IsOk = mr_bool.YES;
ErrorMsg = \"\";
").
@@ -305,7 +403,7 @@ open_system_rng(Result, !IO) :-
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe],
"
- Handle = new java.security.SecureRandom();
+ Handle = new random__system_rng.ML_SystemRandomHandle();
IsOk = bool.YES;
ErrorMsg = \"\";
").
@@ -337,9 +435,14 @@ close_system_rng(Handle, !IO) :-
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe],
"
- // Handle
- IsOk = mr_bool.YES;
- ErrorMsg = \"\";
+ if (Handle.isClosed()) {
+ IsOk = mr_bool.NO;
+ ErrorMsg = \"system RNG handle already closed\";
+ } else {
+ Handle.close();
+ IsOk = mr_bool.YES;
+ ErrorMsg = \"\";
+ }
").
:- pragma foreign_proc("Java",
@@ -347,9 +450,14 @@ close_system_rng(Handle, !IO) :-
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe],
"
- // Handle
- IsOk = bool.YES;
- ErrorMsg = \"\";
+ if (Handle.isClosed()) {
+ IsOk = bool.NO;
+ ErrorMsg = \"system RNG handle already closed\";
+ } else {
+ Handle.close();
+ IsOk = bool.YES;
+ ErrorMsg = \"\";
+ }
").
%---------------------------------------------------------------------------%
@@ -385,11 +493,15 @@ generate_uint8(Handle, U8, !IO) :-
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe],
"
- byte[] bytes = new byte[1];
- Handle.GetBytes(bytes);
- U8 = bytes[0];
- IsOk = mr_bool.YES;
- ErrorMsg = \"\";
+ if (Handle.isClosed()) {
+ U8 = 0;
+ IsOk = mr_bool.NO;
+ ErrorMsg = \"system RNG handle is closed\";
+ } else {
+ U8 = Handle.getByte();
+ IsOk = mr_bool.NO;
+ ErrorMsg = \"\";
+ }
").
:- pragma foreign_proc("Java",
@@ -397,11 +509,15 @@ generate_uint8(Handle, U8, !IO) :-
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe],
"
- byte[] bytes = new byte[1];
- Handle.nextBytes(bytes);
- U8 = bytes[0];
- IsOk = bool.YES;
- ErrorMsg = \"\";
+ if (Handle.isClosed()) {
+ U8 = 0;
+ IsOk = bool.NO;
+ ErrorMsg = \"system RNG handle is closed\";
+ } else {
+ U8 = Handle.getByte();
+ IsOk = bool.YES;
+ ErrorMsg = \"\";
+ }
").
%---------------------------------------------------------------------------%
@@ -437,11 +553,15 @@ generate_uint16(Handle, U16, !IO) :-
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, not_thread_safe],
"
- byte[] bytes = new byte[2];
- Handle.GetBytes(bytes);
- U16 = (ushort) (bytes[1] << 8 | (bytes[0] & 0x00ff));
- IsOk = mr_bool.YES;
- ErrorMsg = \"\";
+ if (Handle.isClosed()) {
+ U16 = 0;
+ IsOk = mr_bool.NO;
+ ErrorMsg = \"system RNG handle is closed\";
+ } else {
+ U16 = Handle.getUShort();
+ IsOk = mr_bool.YES;
+ ErrorMsg = \"\";
+ }
").
:- pragma foreign_proc("Java",
@@ -449,11 +569,15 @@ generate_uint16(Handle, U16, !IO) :-
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe],
"
- byte[] bytes = new byte[2];
- Handle.nextBytes(bytes);
- U16 = (short) (bytes[0] << java.lang.Byte.SIZE | (bytes[1] & 0x00ff));
- IsOk = bool.YES;
- ErrorMsg = \"\";
+ if (Handle.isClosed()) {
+ U16 = 0;
+ IsOk = bool.NO;
+ ErrorMsg = \"system RNG handle is closed\";
+ } else {
+ U16 = Handle.getShort();
+ IsOk = bool.YES;
+ ErrorMsg = \"\";
+ }
").
%---------------------------------------------------------------------------%
@@ -489,11 +613,15 @@ generate_uint32(Handle, U32, !IO) :-
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, not_thread_safe],
"
- byte[] bytes = new byte[4];
- Handle.GetBytes(bytes);
- U32 = (uint) (bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0]);
- IsOk = mr_bool.YES;
- ErrorMsg = \"\";
+ if (Handle.isClosed()) {
+ U32 = 0;
+ IsOk = mr_bool.NO;
+ ErrorMsg = \"system RNG handle is closed\";
+ } else {
+ U32 = Handle.getUInt();
+ IsOk = mr_bool.YES;
+ ErrorMsg = \"\";
+ }
").
:- pragma foreign_proc("Java",
@@ -501,9 +629,15 @@ generate_uint32(Handle, U32, !IO) :-
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe],
"
- U32 = Handle.nextInt();
- IsOk = bool.YES;
- ErrorMsg = \"\";
+ if (Handle.isClosed()) {
+ U32 = 0;
+ IsOk = bool.NO;
+ ErrorMsg = \"system RNG handle is closed\";
+ } else {
+ U32 = Handle.getInt();
+ IsOk = bool.YES;
+ ErrorMsg = \"\";
+ }
").
%---------------------------------------------------------------------------%
@@ -539,19 +673,15 @@ generate_uint64(Handle, U64, !IO) :-
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, not_thread_safe],
"
- byte[] bytes = new byte[8];
- Handle.GetBytes(bytes);
- U64 = (ulong) (
- (ulong) bytes[7] << 56 |
- (ulong) bytes[6] << 48 |
- (ulong) bytes[5] << 40 |
- (ulong) bytes[4] << 32 |
- (ulong) bytes[3] << 24 |
- (ulong) bytes[2] << 16 |
- (ulong) bytes[1] << 8 |
- (ulong) bytes[0]);
- IsOk = mr_bool.YES;
- ErrorMsg = \"\";
+ if (Handle.isClosed()) {
+ U64 = 0;
+ IsOk = mr_bool.NO;
+ ErrorMsg = \"system RNG handle is closed\";
+ } else {
+ U64 = Handle.getULong();
+ IsOk = mr_bool.YES;
+ ErrorMsg = \"\";
+ }
").
:- pragma foreign_proc("Java",
@@ -559,9 +689,15 @@ generate_uint64(Handle, U64, !IO) :-
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe],
"
- U64 = Handle.nextLong();
- IsOk = bool.YES;
- ErrorMsg = \"\";
+ if (Handle.isClosed()) {
+ U64 = 0;
+ IsOk = bool.NO;
+ ErrorMsg = \"system RNG handle is closed\";
+ } else {
+ U64 = Handle.getLong();
+ IsOk = bool.YES;
+ ErrorMsg = \"\";
+ }
").
%---------------------------------------------------------------------------%
More information about the reviews
mailing list