Remove Deprecated CounterSecureRNG, #25978 (#25979)

This commit is contained in:
Patrik Nordwall 2018-12-04 09:50:37 +01:00 committed by Arnout Engelen
parent 2b2f9841b7
commit 00d869724a
13 changed files with 17 additions and 342 deletions

View file

@ -91,6 +91,8 @@ use of these unverified and possibly insecure implementations. The deprecated im
but they can be enabled by using configuration values "DeprecatedAES128CounterSecureRNG" or "DeprecatedAES256CounterSecureRNG" but they can be enabled by using configuration values "DeprecatedAES128CounterSecureRNG" or "DeprecatedAES256CounterSecureRNG"
during the transition period until they have been removed. during the transition period until they have been removed.
*Edit*: `DeprecatedAES128CounterSecureRNG` and `DeprecatedAES256CounterSecureRNG` have been removed since Akka 2.5.19.
### Acknowledgements ### Acknowledgements
We would like to thank Rafał Sumisławski at NetworkedAssets for bringing this issue to our attention and providing We would like to thank Rafał Sumisławski at NetworkedAssets for bringing this issue to our attention and providing

View file

@ -0,0 +1,11 @@
# #25978 Remove deprecated AES random number generators
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.AESCounterBuiltinRNGReSeeder")
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.CounterRNGConstants$")
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.CounterRNGConstants")
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.DeprecatedAES256CounterSecureRNG")
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.DeprecatedAESCounterBuiltinRNG$AESKey")
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.DeprecatedAkkaProvider")
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.DeprecatedAES128CounterSecureRNG")
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.DeprecatedAESCounterBuiltinRNG$")
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.DeprecatedAESCounterBuiltinRNG")
ProblemFilters.exclude[MissingClassProblem]("akka.remote.security.provider.DeprecatedAkkaProvider$")

View file

@ -670,12 +670,6 @@ akka {
# "" or "SecureRandom" => (default) # "" or "SecureRandom" => (default)
# "SHA1PRNG" => Can be slow because of blocking issues on Linux # "SHA1PRNG" => Can be slow because of blocking issues on Linux
# #
# "AES128CounterSecureRNG" and "AES256CounterSecureRNG" were deprecated in Akka
# 2.5.16 and if these configuration values are used it will use the default
# SecureRandom anyway and log a warning. The deprecated implementations are
# not recommended, but they can be enabled by using configuration values
# "DeprecatedAES128CounterSecureRNG" or "DeprecatedAES256CounterSecureRNG"
#
# Setting a value here may require you to supply the appropriate cipher # Setting a value here may require you to supply the appropriate cipher
# suite (see enabled-algorithms section above) # suite (see enabled-algorithms section above)
random-number-generator = "" random-number-generator = ""
@ -1164,12 +1158,6 @@ akka {
# "" or "SecureRandom" => (default) # "" or "SecureRandom" => (default)
# "SHA1PRNG" => Can be slow because of blocking issues on Linux # "SHA1PRNG" => Can be slow because of blocking issues on Linux
# #
# "AES128CounterSecureRNG" and "AES256CounterSecureRNG" were deprecated in Akka
# 2.5.16 and if these configuration values are used it will use the default
# SecureRandom anyway and log a warning. The deprecated implementations are
# not recommended, but they can be enabled by using configuration values
# "DeprecatedAES128CounterSecureRNG" or "DeprecatedAES256CounterSecureRNG"
#
# Setting a value here may require you to supply the appropriate cipher # Setting a value here may require you to supply the appropriate cipher
# suite (see enabled-algorithms section above) # suite (see enabled-algorithms section above)
random-number-generator = "" random-number-generator = ""

View file

@ -24,7 +24,6 @@ import akka.event.LogMarker
import akka.event.Logging import akka.event.Logging
import akka.event.MarkerLoggingAdapter import akka.event.MarkerLoggingAdapter
import akka.japi.Util.immutableSeq import akka.japi.Util.immutableSeq
import akka.remote.security.provider.DeprecatedAkkaProvider
import akka.stream.IgnoreComplete import akka.stream.IgnoreComplete
import akka.stream.TLSClosing import akka.stream.TLSClosing
import akka.stream.TLSRole import akka.stream.TLSRole
@ -233,16 +232,6 @@ object SSLEngineProviderSetup {
log.debug("SSL random number generator set to [SecureRandom]") log.debug("SSL random number generator set to [SecureRandom]")
new SecureRandom new SecureRandom
case r @ ("AES128CounterSecureRNG" | "AES256CounterSecureRNG")
log.warning("SSL random number generator set to deprecated [{}], using [SecureRandom] instead. " +
"The [{}] implementation can be enabled with configuration value [Deprecated{r}], " +
"but that is not recommended.", r, r, r)
new SecureRandom
case r @ ("DeprecatedAES128CounterSecureRNG" | "DeprecatedAES256CounterSecureRNG")
log.warning("SSL random number generator set to deprecated [{}]. Use [SecureRandom] instead.", r)
SecureRandom.getInstance(r, DeprecatedAkkaProvider)
case unknown case unknown
log.warning(LogMarker.Security, "Unknown SSL random number generator [{}] falling back to SecureRandom", unknown) log.warning(LogMarker.Security, "Unknown SSL random number generator [{}] falling back to SecureRandom", unknown)
new SecureRandom new SecureRandom

View file

@ -1,47 +0,0 @@
/*
* Copyright (C) 2009-2018 Lightbend Inc. <https://www.lightbend.com>
*/
package akka.remote.security.provider
import java.security.SecureRandom
import java.util.concurrent.Executors
import SeedSize.Seed128
import scala.concurrent.ExecutionContext
/**
* This class is a wrapper around the 128-bit AESCounterBuiltinRNG AES/CTR PRNG algorithm
* The only method used by netty ssl is engineNextBytes(bytes)
*
*/
@deprecated("Use SecureRandom instead. We cannot prove that this code is correct, see https://doc.akka.io/docs/akka/current/security/2018-08-29-aes-rng.html", "2.5.16")
class DeprecatedAES128CounterSecureRNG extends java.security.SecureRandomSpi {
private val singleThreadPool = ExecutionContext.fromExecutorService(Executors.newSingleThreadExecutor(new AESCounterBuiltinRNGReSeeder))
private val entropySource = new SecureRandom
private val seed = entropySource.generateSeed(Seed128)
private val rng = new DeprecatedAESCounterBuiltinRNG(seed, singleThreadPool)
/**
* This is managed internally by AESCounterBuiltinRNG
*/
override protected def engineSetSeed(seed: Array[Byte]): Unit = ()
/**
* Generates a user-specified number of random bytes.
*
* @param bytes the array to be filled in with random bytes.
*/
override protected def engineNextBytes(bytes: Array[Byte]): Unit = rng.nextBytes(bytes)
/**
* For completeness of SecureRandomSpi API implementation
* Returns the given number of seed bytes.
*
* @param numBytes the number of seed bytes to generate.
* @return the seed bytes.
*/
override protected def engineGenerateSeed(numBytes: Int): Array[Byte] = entropySource.generateSeed(numBytes)
}

View file

@ -1,46 +0,0 @@
/*
* Copyright (C) 2009-2018 Lightbend Inc. <https://www.lightbend.com>
*/
package akka.remote.security.provider
import java.security.SecureRandom
import java.util.concurrent.Executors
import SeedSize.Seed256
import scala.concurrent.ExecutionContext
/**
* This class is a wrapper around the 256-bit AESCounterBuiltinRNG AES/CTR PRNG algorithm
* The only method used by netty ssl is engineNextBytes(bytes)
*/
@deprecated("Use SecureRandom instead. We cannot prove that this code is correct, see https://doc.akka.io/docs/akka/current/security/2018-08-29-aes-rng.html", "2.5.16")
class DeprecatedAES256CounterSecureRNG extends java.security.SecureRandomSpi {
private val singleThreadPool = ExecutionContext.fromExecutorService(Executors.newSingleThreadExecutor(new AESCounterBuiltinRNGReSeeder))
private val entropySource = new SecureRandom
private val seed = entropySource.generateSeed(Seed256)
private val rng = new DeprecatedAESCounterBuiltinRNG(seed, singleThreadPool)
/**
* This is managed internally by AESCounterBuiltinRNG
*/
override protected def engineSetSeed(seed: Array[Byte]): Unit = ()
/**
* Generates a user-specified number of random bytes.
*
* @param bytes the array to be filled in with random bytes.
*/
override protected def engineNextBytes(bytes: Array[Byte]): Unit = rng.nextBytes(bytes)
/**
* For completeness of SecureRandomSpi API implementation
* Returns the given number of seed bytes.
*
* @param numBytes the number of seed bytes to generate.
* @return the seed bytes.
*/
override protected def engineGenerateSeed(numBytes: Int): Array[Byte] = entropySource.generateSeed(numBytes)
}

View file

@ -1,147 +0,0 @@
/*
* Copyright (C) 2016-2018 Lightbend Inc. <https://www.lightbend.com>
*/
package akka.remote.security.provider
import java.security.{ Key, SecureRandom }
import java.util.Random
import java.util.concurrent.ThreadFactory
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import akka.annotation.InternalApi
import scala.concurrent.duration.{ Duration, FiniteDuration }
import scala.concurrent.{ Await, ExecutionContext, Future, duration }
/**
* INTERNAL API
*
* We cannot prove that this code is correct and it will therefore be removed
* with AES128CounterSecureRNG and AES256CounterSecureRNG. See security
* vulnerability https://doc.akka.io/docs/akka/current/security/2018-08-29-aes-rng.html
*
* This class is a Scala implementation of AESCounterRNG algorithm
* patterned after org.uncommons.maths.random by Daniel Dyer (Apache License 2.0)
*
* Non-linear random number generator based on the AES block cipher in counter mode.
* Uses the seed as a key to encrypt a 128-bit counter using AES(Rijndael).
*
* Keys larger than 128-bit for the AES cipher require
* the inconvenience of installing the unlimited strength cryptography policy
* files for the Java platform. Larger keys may be used (192 or 256 bits) but if the
* cryptography policy files are not installed, a
* java.security.GeneralSecurityException will be thrown.
*
* NOTE: this class is not serializable
*/
@InternalApi
private[akka] class DeprecatedAESCounterBuiltinRNG(val seed: Array[Byte], implicit val executionContext: ExecutionContext,
val reseedingThreshold: Long = CounterRNGConstants.ReseedingThreshold,
val reseedingDeadline: Long = CounterRNGConstants.ReseedingDeadline,
val reseedingTimeout: Duration = CounterRNGConstants.ReseedingTimeout) extends Random {
import CounterRNGConstants._
private val entropySource = new SecureRandom
// mutable state below, concurrent accesses need synchronized or lock
private var index: Int = 0
private var currentBlock: Array[Byte] = null
private var reseedFuture: Future[Array[Byte]] = null
private var bitsSinceSeeding: Long = 0
private val cipher = Cipher.getInstance("AES/CTR/NoPadding")
// this algorithm can be further improved by better selection of the iv
// here and at re-seeding time further below
private val ivArr = Array.fill[Byte](CounterSizeBytes)(0)
ivArr(0) = (ivArr(0) + 1).toByte
private val ivSpec = new IvParameterSpec(ivArr)
cipher.init(Cipher.ENCRYPT_MODE, new this.AESKey(seed), ivSpec)
private val zeros: Array[Byte] = Array.fill[Byte](CounterSizeBytes)(0)
@Override
override protected def next(bits: Int): Int = synchronized {
// random result generation phase - if there is not enough bits in the currentBlock
// we generate some more with AES/CTR
bitsSinceSeeding += bits
if (currentBlock == null || currentBlock.length - index < 4) {
try {
currentBlock = cipher.update(zeros)
index = 0
} catch {
case ex: Exception
// Generally Cipher.update() from nextBlock may throw various exceptions.
// However this should never happen. If initialisation succeeds without exceptions
// we should be able to proceed indefinitely without exceptions.
throw new IllegalStateException("Failed creating next random block.", ex)
}
}
// now, enough bits in currentBlock, generate pseudo-random result
val result = (BitwiseByteToInt & currentBlock(index + 3)) |
((BitwiseByteToInt & currentBlock(index + 2)) << 8) |
((BitwiseByteToInt & currentBlock(index + 1)) << 16) |
((BitwiseByteToInt & currentBlock(index)) << 24)
// re-seeding phase
// first, we check if reseedingThreshold is exceeded to see if new entropy is required
// we can still proceed without it, but we should ask for it
if (bitsSinceSeeding > reseedingThreshold) {
if (reseedFuture == null) {
// ask for a seed and process async on a separate thread using AESCounterBuiltinRNGReSeeder threadpool
reseedFuture = Future { entropySource.generateSeed(seed.length) }
}
// check if reseedingDeadline is exceeded - in that case we cannot proceed, as that would be insecure
// we need to block on the future to wait for entropy
if (bitsSinceSeeding > reseedingDeadline) {
try {
Await.ready(reseedFuture, reseedingTimeout)
} catch {
case ex: Exception
Console.err.println(s"[ERROR] AESCounterBuiltinRNG re-seeding failed or timed out after ${reseedingTimeout.toSeconds.toString}s !")
}
}
// check if future has completed and retrieve additional entropy if that is the case
if (reseedFuture != null && reseedFuture.isCompleted) {
if (reseedFuture.value.get.isSuccess) { // we have re-seeded with success
val newSeed = reseedFuture.value.get.get // this is safe
cipher.init(Cipher.ENCRYPT_MODE, new this.AESKey(newSeed), ivSpec)
currentBlock = null
bitsSinceSeeding = 0 // reset re-seeding counter
}
reseedFuture = null // request creation of new seed when needed
}
}
index += 4
result >>> (32 - bits)
}
/**
* Trivial key implementation for use with AES cipher.
*/
final private class AESKey(val keyData: Array[Byte]) extends Key {
def getAlgorithm: String = "AES"
def getFormat: String = "RAW"
def getEncoded: Array[Byte] = keyData
}
}
private object CounterRNGConstants {
final val CounterSizeBytes = 16
final val BitwiseByteToInt = 0x000000FF
final val ReseedingThreshold = 1000000000L // threshold for requesting new entropy (should give us ample time to re-seed)
final val ReseedingDeadline = 140737488355328L // deadline for obtaining new entropy 2^47 safe as per SP800-90
final val ReseedingTimeout: FiniteDuration = Duration.apply(5, duration.MINUTES) // timeout for re-seeding (on Linux read from /dev/random)
}
private class AESCounterBuiltinRNGReSeeder extends ThreadFactory {
override def newThread(r: Runnable): Thread = {
val thread = new Thread(r, "AESCounterBuiltinRNGReSeeder")
thread.setDaemon(true)
thread
}
}

View file

@ -1,28 +0,0 @@
/*
* Copyright (C) 2009-2018 Lightbend Inc. <https://www.lightbend.com>
*/
package akka.remote.security.provider
import java.security.{ PrivilegedAction, AccessController, Provider }
/**
* A provider that for AES128CounterRNGFast, a cryptographically secure random number generator through SecureRandom
*
*/
@deprecated("Use SecureRandom instead. We cannot prove that this code is correct, see https://doc.akka.io/docs/akka/current/security/2018-08-29-aes-rng.html", "2.5.16")
object DeprecatedAkkaProvider extends Provider("Akka", 1.0, "Akka provider 1.0 that implements a secure AES random number generator") {
AccessController.doPrivileged(new PrivilegedAction[this.type] {
def run = {
//SecureRandom
put("SecureRandom.DeprecatedAES128CounterSecureRNG", classOf[DeprecatedAES128CounterSecureRNG].getName)
put("SecureRandom.DeprecatedAES256CounterSecureRNG", classOf[DeprecatedAES256CounterSecureRNG].getName)
//Implementation type: software or hardware
put("SecureRandom.DeprecatedAES128CounterSecureRNG ImplementedIn", "Software")
put("SecureRandom.DeprecatedAES256CounterSecureRNG ImplementedIn", "Software")
null //Magic null is magic
}
})
}

View file

@ -7,7 +7,6 @@ package akka.remote.transport.netty
import java.security._ import java.security._
import akka.japi.Util._ import akka.japi.Util._
import akka.remote.security.provider.DeprecatedAkkaProvider
import com.typesafe.config.Config import com.typesafe.config.Config
import org.jboss.netty.handler.ssl.SslHandler import org.jboss.netty.handler.ssl.SslHandler
@ -45,9 +44,6 @@ private[akka] class SSLSettings(config: Config) {
*/ */
private[akka] object NettySSLSupport { private[akka] object NettySSLSupport {
// TODO is this needed in Artery TLS?
Security addProvider DeprecatedAkkaProvider
/** /**
* Construct a SSLHandler which can be inserted into a Netty server/client pipeline * Construct a SSLHandler which can be inserted into a Netty server/client pipeline
*/ */

View file

@ -73,7 +73,6 @@ object RemotingSpec {
key-password = "changeme" key-password = "changeme"
trust-store-password = "changeme" trust-store-password = "changeme"
protocol = "TLSv1.2" protocol = "TLSv1.2"
random-number-generator = "AES128CounterSecureRNG"
enabled-algorithms = [TLS_RSA_WITH_AES_128_CBC_SHA] enabled-algorithms = [TLS_RSA_WITH_AES_128_CBC_SHA]
} }

View file

@ -72,10 +72,7 @@ object Configuration {
val rng = sslEngineProvider.createSecureRandom() val rng = sslEngineProvider.createSecureRandom()
rng.nextInt() // Has to work rng.nextInt() // Has to work
val sRng = settings.SSLRandomNumberGenerator match { val sRng = settings.SSLRandomNumberGenerator
case "AES128CounterSecureRNG" | "AES256CounterSecureRNG" ""
case other other
}
if (rng.getAlgorithm != sRng && sRng != "") if (rng.getAlgorithm != sRng && sRng != "")
throw new NoSuchAlgorithmException(sRng) throw new NoSuchAlgorithmException(sRng)
@ -97,14 +94,6 @@ object Configuration {
class Ticket1978SHA1PRNGSpec extends Ticket1978CommunicationSpec(getCipherConfig("SHA1PRNG", "TLS_RSA_WITH_AES_128_CBC_SHA")) class Ticket1978SHA1PRNGSpec extends Ticket1978CommunicationSpec(getCipherConfig("SHA1PRNG", "TLS_RSA_WITH_AES_128_CBC_SHA"))
class Ticket1978AES128CounterSecureRNGSpec extends Ticket1978CommunicationSpec(getCipherConfig("AES128CounterSecureRNG", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"))
class Ticket1978DeprecatedAES128CounterSecureRNGSpec extends Ticket1978CommunicationSpec(getCipherConfig("DeprecatedAES128CounterSecureRNG", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"))
class Ticket1978AES256CounterSecureRNGSpec extends Ticket1978CommunicationSpec(getCipherConfig("AES256CounterSecureRNG", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"))
class Ticket1978DeprecatedAES256CounterSecureRNGSpec extends Ticket1978CommunicationSpec(getCipherConfig("DeprecatedAES256CounterSecureRNG", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"))
class Ticket1978DefaultRNGSecureSpec extends Ticket1978CommunicationSpec(getCipherConfig("", "TLS_RSA_WITH_AES_128_CBC_SHA")) class Ticket1978DefaultRNGSecureSpec extends Ticket1978CommunicationSpec(getCipherConfig("", "TLS_RSA_WITH_AES_128_CBC_SHA"))
class Ticket1978CrappyRSAWithMD5OnlyHereToMakeSureThingsWorkSpec extends Ticket1978CommunicationSpec(getCipherConfig("", "SSL_RSA_WITH_NULL_MD5")) class Ticket1978CrappyRSAWithMD5OnlyHereToMakeSureThingsWorkSpec extends Ticket1978CommunicationSpec(getCipherConfig("", "SSL_RSA_WITH_NULL_MD5"))

View file

@ -9,7 +9,7 @@ import akka.remote.transport.netty.SSLSettings
class Ticket1978ConfigSpec extends AkkaSpec(""" class Ticket1978ConfigSpec extends AkkaSpec("""
akka.remote.netty.ssl.security { akka.remote.netty.ssl.security {
random-number-generator = "AES128CounterSecureRNG" random-number-generator = "SecureRandom"
} }
""") with ImplicitSender with DefaultTimeout { """) with ImplicitSender with DefaultTimeout {
@ -24,7 +24,7 @@ class Ticket1978ConfigSpec extends AkkaSpec("""
settings.SSLTrustStorePassword should ===("changeme") settings.SSLTrustStorePassword should ===("changeme")
settings.SSLProtocol should ===("TLSv1.2") settings.SSLProtocol should ===("TLSv1.2")
settings.SSLEnabledAlgorithms should ===(Set("TLS_RSA_WITH_AES_128_CBC_SHA")) settings.SSLEnabledAlgorithms should ===(Set("TLS_RSA_WITH_AES_128_CBC_SHA"))
settings.SSLRandomNumberGenerator should ===("AES128CounterSecureRNG") settings.SSLRandomNumberGenerator should ===("SecureRandom")
} }
} }
} }

View file

@ -34,34 +34,6 @@ class TlsTcpWithSHA1PRNGSpec extends TlsTcpSpec(ConfigFactory.parseString("""
} }
""")) """))
class TlsTcpWithAES128CounterSecureRNGSpec extends TlsTcpSpec(ConfigFactory.parseString("""
akka.remote.artery.ssl.config-ssl-engine {
random-number-generator = "AES128CounterSecureRNG"
enabled-algorithms = ["TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"]
}
"""))
class TlsTcpWithDeprecatedAES128CounterSecureRNGSpec extends TlsTcpSpec(ConfigFactory.parseString("""
akka.remote.artery.ssl.config-ssl-engine {
random-number-generator = "DeprecatedAES128CounterSecureRNG"
enabled-algorithms = ["TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"]
}
"""))
class TlsTcpWithAES256CounterSecureRNGSpec extends TlsTcpSpec(ConfigFactory.parseString("""
akka.remote.artery.ssl.config-ssl-engine {
random-number-generator = "AES256CounterSecureRNG"
enabled-algorithms = ["TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"]
}
"""))
class TlsTcpWithDeprecatedAES256CounterSecureRNGSpec extends TlsTcpSpec(ConfigFactory.parseString("""
akka.remote.artery.ssl.config-ssl-engine {
random-number-generator = "DeprecatedAES256CounterSecureRNG"
enabled-algorithms = ["TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA"]
}
"""))
class TlsTcpWithDefaultRNGSecureSpec extends TlsTcpSpec(ConfigFactory.parseString(""" class TlsTcpWithDefaultRNGSecureSpec extends TlsTcpSpec(ConfigFactory.parseString("""
akka.remote.artery.ssl.config-ssl-engine { akka.remote.artery.ssl.config-ssl-engine {
random-number-generator = "" random-number-generator = ""
@ -102,10 +74,7 @@ abstract class TlsTcpSpec(config: Config)
val rng = provider.createSecureRandom() val rng = provider.createSecureRandom()
rng.nextInt() // Has to work rng.nextInt() // Has to work
val sRng = provider.SSLRandomNumberGenerator match { val sRng = provider.SSLRandomNumberGenerator
case "AES128CounterSecureRNG" | "AES256CounterSecureRNG" ""
case other other
}
if (rng.getAlgorithm != sRng && sRng != "") if (rng.getAlgorithm != sRng && sRng != "")
throw new NoSuchAlgorithmException(sRng) throw new NoSuchAlgorithmException(sRng)