forked from hyperledger-web3j/web3j
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added secure random implementation for Android (hyperledger-web3j#146).
- Loading branch information
Showing
5 changed files
with
167 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
104 changes: 104 additions & 0 deletions
104
core/src/main/java/org/web3j/crypto/LinuxSecureRandom.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/* | ||
* Copyright 2013 Google Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.web3j.crypto; | ||
|
||
import java.io.DataInputStream; | ||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.io.FileNotFoundException; | ||
import java.io.IOException; | ||
import java.security.Provider; | ||
import java.security.SecureRandomSpi; | ||
import java.security.Security; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
|
||
/** | ||
* Implementation from | ||
* <a href="https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/org/bitcoinj/crypto/LinuxSecureRandom.java">BitcoinJ implementation</a> | ||
* | ||
* A SecureRandom implementation that is able to override the standard JVM provided implementation, and which simply | ||
* serves random numbers by reading /dev/urandom. That is, it delegates to the kernel on UNIX systems and is unusable on | ||
* other platforms. Attempts to manually set the seed are ignored. There is no difference between seed bytes and | ||
* non-seed bytes, they are all from the same source. | ||
*/ | ||
public class LinuxSecureRandom extends SecureRandomSpi { | ||
private static final FileInputStream urandom; | ||
|
||
private static class LinuxSecureRandomProvider extends Provider { | ||
public LinuxSecureRandomProvider() { | ||
super("LinuxSecureRandom", 1.0, "A Linux specific random number provider that uses /dev/urandom"); | ||
put("SecureRandom.LinuxSecureRandom", LinuxSecureRandom.class.getName()); | ||
} | ||
} | ||
|
||
private static final Logger log = LoggerFactory.getLogger(LinuxSecureRandom.class); | ||
|
||
static { | ||
try { | ||
File file = new File("/dev/urandom"); | ||
// This stream is deliberately leaked. | ||
urandom = new FileInputStream(file); | ||
if (urandom.read() == -1) | ||
throw new RuntimeException("/dev/urandom not readable?"); | ||
// Now override the default SecureRandom implementation with this one. | ||
int position = Security.insertProviderAt(new LinuxSecureRandomProvider(), 1); | ||
|
||
if (position != -1) | ||
log.info("Secure randomness will be read from {} only.", file); | ||
else | ||
log.info("Randomness is already secure."); | ||
} catch (FileNotFoundException e) { | ||
// Should never happen. | ||
log.error("/dev/urandom does not appear to exist or is not openable"); | ||
throw new RuntimeException(e); | ||
} catch (IOException e) { | ||
log.error("/dev/urandom does not appear to be readable"); | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
private final DataInputStream dis; | ||
|
||
public LinuxSecureRandom() { | ||
// DataInputStream is not thread safe, so each random object has its own. | ||
dis = new DataInputStream(urandom); | ||
} | ||
|
||
@Override | ||
protected void engineSetSeed(byte[] bytes) { | ||
// Ignore. | ||
} | ||
|
||
@Override | ||
protected void engineNextBytes(byte[] bytes) { | ||
try { | ||
dis.readFully(bytes); // This will block until all the bytes can be read. | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); // Fatal error. Do not attempt to recover from this. | ||
} | ||
} | ||
|
||
@Override | ||
protected byte[] engineGenerateSeed(int i) { | ||
byte[] bits = new byte[i]; | ||
engineNextBytes(bits); | ||
return bits; | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
core/src/main/java/org/web3j/crypto/SecureRandomUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package org.web3j.crypto; | ||
|
||
import java.security.SecureRandom; | ||
|
||
/** | ||
* Utility class for working with SecureRandom implementation. | ||
* | ||
* This is to address issues with SecureRandom on Android. For more information, refer to the | ||
* following <a href="https://github.com/web3j/web3j/issues/146">issue</a>. | ||
*/ | ||
final class SecureRandomUtils { | ||
|
||
private static final SecureRandom SECURE_RANDOM; | ||
|
||
static { | ||
if (isAndroidRuntime()) { | ||
new LinuxSecureRandom(); | ||
} | ||
SECURE_RANDOM = new java.security.SecureRandom(); | ||
} | ||
|
||
static java.security.SecureRandom secureRandom() { | ||
return SECURE_RANDOM; | ||
} | ||
|
||
// Taken from BitcoinJ implementation | ||
// https://github.com/bitcoinj/bitcoinj/blob/3cb1f6c6c589f84fe6e1fb56bf26d94cccc85429/core/src/main/java/org/bitcoinj/core/Utils.java#L573 | ||
private static int isAndroid = -1; | ||
static boolean isAndroidRuntime() { | ||
if (isAndroid == -1) { | ||
final String runtime = System.getProperty("java.runtime.name"); | ||
isAndroid = (runtime != null && runtime.equals("Android Runtime")) ? 1 : 0; | ||
} | ||
return isAndroid == 1; | ||
} | ||
|
||
private SecureRandomUtils() { } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
core/src/test/java/org/web3j/crypto/SecureRandomUtilsTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.web3j.crypto; | ||
|
||
import org.junit.Test; | ||
|
||
import static org.junit.Assert.assertFalse; | ||
import static org.web3j.crypto.SecureRandomUtils.isAndroidRuntime; | ||
import static org.web3j.crypto.SecureRandomUtils.secureRandom; | ||
|
||
public class SecureRandomUtilsTest { | ||
|
||
@Test | ||
public void testSecureRandom() { | ||
secureRandom().nextInt(); | ||
} | ||
|
||
@Test | ||
public void testIsNotAndroidRuntime() { | ||
assertFalse(isAndroidRuntime()); | ||
} | ||
} |