aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/com/zeapo/pwdstore/pwgen
diff options
context:
space:
mode:
authorHarsh Shandilya <msfjarvis@gmail.com>2019-01-02 22:44:52 +0530
committerحسين <zidhussein@gmail.com>2019-01-02 17:14:52 +0000
commitc200566bcaec971e1756afe5ebf96baf09e88816 (patch)
tree15e692cdaffe08861df40849e31154409be96b46 /app/src/main/java/com/zeapo/pwdstore/pwgen
parentd5e589d7e48d4f44a052ecbf2817f5051bd1005f (diff)
downloadHardenedPass-c200566bcaec971e1756afe5ebf96baf09e88816.tar.gz
HardenedPass-c200566bcaec971e1756afe5ebf96baf09e88816.zip
Bump minSdk to 21 (#466)
* Bump minSdk to 21 Signed-off-by: Harsh Shandilya <msfjarvis@gmail.com> * PasswordGenerator: Constify things Signed-off-by: Harsh Shandilya <msfjarvis@gmail.com> * Deprecate PRNG fixes The problem being fixed doesn't exist on SDK 21 and above. Signed-off-by: Harsh Shandilya <msfjarvis@gmail.com> * treewide: Switch to lambdas Signed-off-by: Harsh Shandilya <msfjarvis@gmail.com> * treewide: Formatting fixes Signed-off-by: Harsh Shandilya <msfjarvis@gmail.com> * treewide: Remove useless casts and add missing annotations Signed-off-by: Harsh Shandilya <msfjarvis@gmail.com>
Diffstat (limited to 'app/src/main/java/com/zeapo/pwdstore/pwgen')
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/pwgen/PRNGFixes.kt310
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/pwgen/PasswordGenerator.kt25
2 files changed, 12 insertions, 323 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/pwgen/PRNGFixes.kt b/app/src/main/java/com/zeapo/pwdstore/pwgen/PRNGFixes.kt
deleted file mode 100644
index 98c3735f..00000000
--- a/app/src/main/java/com/zeapo/pwdstore/pwgen/PRNGFixes.kt
+++ /dev/null
@@ -1,310 +0,0 @@
-package com.zeapo.pwdstore.pwgen
-
-/*
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will Google be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, as long as the origin is not misrepresented.
- */
-
-import android.os.Build
-import android.os.Process
-import android.util.Log
-
-import java.io.ByteArrayOutputStream
-import java.io.DataInputStream
-import java.io.DataOutputStream
-import java.io.File
-import java.io.FileInputStream
-import java.io.FileOutputStream
-import java.io.IOException
-import java.io.OutputStream
-import java.io.UnsupportedEncodingException
-import java.security.NoSuchAlgorithmException
-import java.security.Provider
-import java.security.SecureRandom
-import java.security.SecureRandomSpi
-import java.security.Security
-
-/**
- * Fixes for the output of the default PRNG having low entropy.
- *
- * The fixes need to be applied via [.apply] before any use of Java
- * Cryptography Architecture primitives. A good place to invoke them is in the
- * application's `onCreate`.
- */
-object PRNGFixes {
-
- private const val VERSION_CODE_JELLY_BEAN_MR2 = 18
- private val BUILD_FINGERPRINT_AND_DEVICE_SERIAL = buildFingerprintAndDeviceSerial
-
- private val buildFingerprintAndDeviceSerial: ByteArray
- get() {
- val result = StringBuilder()
- val fingerprint = Build.FINGERPRINT
- if (fingerprint != null) {
- result.append(fingerprint)
- }
- // TODO: Build#SERIAL is deprecated and should be removed or replaced
- val serial = Build.SERIAL
- if (serial != null) {
- result.append(serial)
- }
- try {
- return result.toString().toByteArray(charset("UTF-8"))
- } catch (e: UnsupportedEncodingException) {
- throw RuntimeException("UTF-8 encoding not supported")
- }
- }
-
- /**
- * Applies all fixes.
- *
- * @throws SecurityException if a fix is needed but could not be applied.
- */
- fun apply() {
- applyOpenSSLFix()
- installLinuxPRNGSecureRandom()
- }
-
- /**
- * Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
- * fix is not needed.
- *
- * @throws SecurityException if the fix is needed but could not be applied.
- */
- @Throws(SecurityException::class)
- private fun applyOpenSSLFix() {
- if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
- // No need to apply the fix
- return
- }
-
- try {
- // Mix in the device- and invocation-specific seed.
- Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
- .getMethod("RAND_seed", ByteArray::class.java)
- .invoke(null, generateSeed())
-
- // Mix output of Linux PRNG into OpenSSL's PRNG
- val bytesRead = Class.forName(
- "org.apache.harmony.xnet.provider.jsse.NativeCrypto"
- )
- .getMethod("RAND_load_file", String::class.java, Long::class.javaPrimitiveType)
- .invoke(null, "/dev/urandom", 1024) as Int
- if (bytesRead != 1024) {
- throw IOException(
- "Unexpected number of bytes read from Linux PRNG: $bytesRead"
- )
- }
- } catch (e: Exception) {
- throw SecurityException("Failed to seed OpenSSL PRNG", e)
- }
- }
-
- /**
- * Installs a Linux PRNG-backed `SecureRandom` implementation as the
- * default. Does nothing if the implementation is already the default or if
- * there is not need to install the implementation.
- *
- * @throws SecurityException if the fix is needed but could not be applied.
- */
- @Throws(SecurityException::class)
- private fun installLinuxPRNGSecureRandom() {
- if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
- // No need to apply the fix
- return
- }
-
- // Install a Linux PRNG-based SecureRandom implementation as the
- // default, if not yet installed.
- val secureRandomProviders = Security.getProviders("SecureRandom.SHA1PRNG")
- if (secureRandomProviders == null
- || secureRandomProviders.isEmpty()
- || LinuxPRNGSecureRandomProvider::class.java != secureRandomProviders[0].javaClass
- ) {
- Security.insertProviderAt(LinuxPRNGSecureRandomProvider(), 1)
- }
-
- // Assert that new SecureRandom() and
- // SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
- // by the Linux PRNG-based SecureRandom implementation.
- val rng1 = SecureRandom()
- if (LinuxPRNGSecureRandomProvider::class.java != rng1.provider.javaClass) {
- throw SecurityException(
- "new SecureRandom() backed by wrong Provider: " + rng1.provider.javaClass
- )
- }
-
- val rng2: SecureRandom
- try {
- rng2 = SecureRandom.getInstance("SHA1PRNG")
- } catch (e: NoSuchAlgorithmException) {
- throw SecurityException("SHA1PRNG not available", e)
- }
-
- if (LinuxPRNGSecureRandomProvider::class.java != rng2.provider.javaClass) {
- throw SecurityException(
- "SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
- + " Provider: " + rng2.provider.javaClass
- )
- }
- }
-
- /**
- * `Provider` of `SecureRandom` engines which pass through
- * all requests to the Linux PRNG.
- */
- private class LinuxPRNGSecureRandomProvider :
- Provider("LinuxPRNG", 1.0, "A Linux-specific random number provider that uses" + " /dev/urandom") {
- init {
- // Although /dev/urandom is not a SHA-1 PRNG, some apps
- // explicitly request a SHA1PRNG SecureRandom and we thus need to
- // prevent them from getting the default implementation whose output
- // may have low entropy.
- put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom::class.java.name)
- put("SecureRandom.SHA1PRNG ImplementedIn", "Software")
- }
- }
-
- /**
- * [SecureRandomSpi] which passes all requests to the Linux PRNG
- * (`/dev/urandom`).
- */
- class LinuxPRNGSecureRandom : SecureRandomSpi() {
-
- /**
- * Whether this engine instance has been seeded. This is needed because
- * each instance needs to seed itself if the client does not explicitly
- * seed it.
- */
- private var mSeeded: Boolean = false
-
- private// NOTE: Consider inserting a BufferedInputStream between
- // DataInputStream and FileInputStream if you need higher
- // PRNG output performance and can live with future PRNG
- // output being pulled into this process prematurely.
- val urandomInputStream: DataInputStream
- get() = synchronized(sLock) {
- if (sUrandomIn == null) {
- try {
- sUrandomIn = DataInputStream(
- FileInputStream(URANDOM_FILE)
- )
- } catch (e: IOException) {
- throw SecurityException(
- "Failed to open "
- + URANDOM_FILE + " for reading", e
- )
- }
- }
- return sUrandomIn as DataInputStream
- }
-
- private val urandomOutputStream: OutputStream
- @Throws(IOException::class)
- get() = synchronized(sLock) {
- if (sUrandomOut == null) {
- sUrandomOut = FileOutputStream(URANDOM_FILE)
- }
- return sUrandomOut as OutputStream
- }
-
- @Synchronized
- override fun engineSetSeed(bytes: ByteArray) {
- try {
- val out: OutputStream = urandomOutputStream
- out.write(bytes)
- out.flush()
- } catch (e: IOException) {
- // On a small fraction of devices /dev/urandom is not writable.
- // Log and ignore.
- Log.w(
- PRNGFixes::class.java.simpleName,
- "Failed to mix seed into $URANDOM_FILE"
- )
- } finally {
- mSeeded = true
- }
- }
-
- @Synchronized
- override fun engineNextBytes(bytes: ByteArray) {
- if (!mSeeded) {
- // Mix in the device- and invocation-specific seed.
- engineSetSeed(generateSeed())
- }
-
- try {
- val `in`: DataInputStream = urandomInputStream
- synchronized(`in`) {
- `in`.readFully(bytes)
- }
- } catch (e: IOException) {
- throw SecurityException(
- "Failed to read from $URANDOM_FILE", e
- )
- }
- }
-
- override fun engineGenerateSeed(size: Int): ByteArray {
- val seed = ByteArray(size)
- engineNextBytes(seed)
- return seed
- }
-
- companion object {
-
- /*
- * IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed
- * are passed through to the Linux PRNG (/dev/urandom). Instances of
- * this class seed themselves by mixing in the current time, PID, UID,
- * build fingerprint, and hardware serial number (where available) into
- * Linux PRNG.
- *
- * Concurrency: Read requests to the underlying Linux PRNG are
- * serialized (on sLock) to ensure that multiple threads do not get
- * duplicated PRNG output.
- */
-
- private val URANDOM_FILE = File("/dev/urandom")
-
- private val sLock = Any()
-
- /**
- * Input stream for reading from Linux PRNG or `null` if not yet
- * opened.
- */
- private var sUrandomIn: DataInputStream? = null
-
- /**
- * Output stream for writing to Linux PRNG or `null` if not yet
- * opened.
- */
- private var sUrandomOut: OutputStream? = null
- }
- }
-
- /**
- * Generates a device- and invocation-specific seed to be mixed into the
- * Linux PRNG.
- */
- private fun generateSeed(): ByteArray {
- try {
- val seedBuffer = ByteArrayOutputStream()
- val seedBufferOut = DataOutputStream(seedBuffer)
- seedBufferOut.writeLong(System.currentTimeMillis())
- seedBufferOut.writeLong(System.nanoTime())
- seedBufferOut.writeInt(Process.myPid())
- seedBufferOut.writeInt(Process.myUid())
- seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL)
- seedBufferOut.close()
- return seedBuffer.toByteArray()
- } catch (e: IOException) {
- throw SecurityException("Failed to generate seed", e)
- }
- }
-}
diff --git a/app/src/main/java/com/zeapo/pwdstore/pwgen/PasswordGenerator.kt b/app/src/main/java/com/zeapo/pwdstore/pwgen/PasswordGenerator.kt
index 0374236c..3a7dcc27 100644
--- a/app/src/main/java/com/zeapo/pwdstore/pwgen/PasswordGenerator.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/pwgen/PasswordGenerator.kt
@@ -1,26 +1,25 @@
package com.zeapo.pwdstore.pwgen
import android.content.Context
-import android.content.SharedPreferences
import java.util.ArrayList
object PasswordGenerator {
- internal val DIGITS = 0x0001
- internal val UPPERS = 0x0002
- internal val SYMBOLS = 0x0004
- internal val AMBIGUOUS = 0x0008
- internal val NO_VOWELS = 0x0010
+ internal const val DIGITS = 0x0001
+ internal const val UPPERS = 0x0002
+ internal const val SYMBOLS = 0x0004
+ internal const val AMBIGUOUS = 0x0008
+ internal const val NO_VOWELS = 0x0010
- internal val DIGITS_STR = "0123456789"
- internal val UPPERS_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- internal val LOWERS_STR = "abcdefghijklmnopqrstuvwxyz"
- internal val SYMBOLS_STR = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
- internal val AMBIGUOUS_STR = "B8G6I1l0OQDS5Z2"
- internal val VOWELS_STR = "01aeiouyAEIOUY"
+ internal const val DIGITS_STR = "0123456789"
+ internal const val UPPERS_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ internal const val LOWERS_STR = "abcdefghijklmnopqrstuvwxyz"
+ internal const val SYMBOLS_STR = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
+ internal const val AMBIGUOUS_STR = "B8G6I1l0OQDS5Z2"
+ internal const val VOWELS_STR = "01aeiouyAEIOUY"
// No a, c, n, h, H, C, 1, N
- private val pwOptions = "0ABsvy"
+ private const val pwOptions = "0ABsvy"
/**
* Sets password generation preferences.