summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Hook <dgh@cryptoworkshop.com>2022-03-23 14:26:36 +1100
committerDavid Hook <dgh@cryptoworkshop.com>2022-03-23 14:26:36 +1100
commit377a6f0d2bf1c01cd297c491998245056b8ebff7 (patch)
treefee0cc5c52b05700fd63bdb6df9ef498ddf0e9a1
parentMerge remote-tracking branch 'refs/remotes/origin/master' (diff)
downloadBouncyCastle.NET-ed25519-377a6f0d2bf1c01cd297c491998245056b8ebff7.tar.xz
added RSA/EC checks
-rw-r--r--crypto/src/asn1/anssi/ANSSINamedCurves.cs2
-rw-r--r--crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs16
-rw-r--r--crypto/src/asn1/gm/GMNamedCurves.cs4
-rw-r--r--crypto/src/asn1/sec/SECNamedCurves.cs30
-rw-r--r--crypto/src/asn1/x9/X962NamedCurves.cs14
-rw-r--r--crypto/src/crypto/parameters/RsaKeyParameters.cs21
-rw-r--r--crypto/src/math/ec/ECCurve.cs82
7 files changed, 135 insertions, 34 deletions
diff --git a/crypto/src/asn1/anssi/ANSSINamedCurves.cs b/crypto/src/asn1/anssi/ANSSINamedCurves.cs
index 48017fc2a..3a9e4dd03 100644
--- a/crypto/src/asn1/anssi/ANSSINamedCurves.cs
+++ b/crypto/src/asn1/anssi/ANSSINamedCurves.cs
@@ -48,7 +48,7 @@ namespace Org.BouncyCastle.Asn1.Anssi
                 BigInteger n = FromHex("F1FD178C0B3AD58F10126DE8CE42435B53DC67E140D2BF941FFDD459C6D655E1");
                 BigInteger h = BigInteger.One;
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
diff --git a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
index 121843ada..5ac8cadfe 100644
--- a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
+++ b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
@@ -58,7 +58,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                     mod_p,
                     FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94"),
                     FromHex("A6"),
-                    mod_q, BigInteger.One));
+                    mod_q, BigInteger.One, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -93,7 +93,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                     mod_p,
                     FromHex("8000000000000000000000000000000000000000000000000000000000000C96"),
                     FromHex("3E1AF419A269A5F866A7D3C25C3DF80AE979259373FF2B182F49D4CE7E1BBC8B"),
-                    mod_q, BigInteger.One));
+                    mod_q, BigInteger.One, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -128,7 +128,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                     mod_p,
                     FromHex("9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598"),
                     FromHex("805A"),
-                    mod_q, BigInteger.One));
+                    mod_q, BigInteger.One, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -163,7 +163,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                     mod_p,
                     FromHex("9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598"),
                     FromHex("805A"),
-                    mod_q, BigInteger.One));
+                    mod_q, BigInteger.One, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -198,7 +198,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                     mod_p,
                     FromHex("C2173F1513981673AF4892C23035A27CE25E2013BF95AA33B22C656F277E7335"),
                     FromHex("295F9BAE7428ED9CCC20E7C359A9D41A22FCCD9108E17BF7BA9337A6F8AE9513"),
-                    mod_q, BigInteger.Four));
+                    mod_q, BigInteger.Four, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -233,7 +233,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                     mod_p,
                     FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4"),
                     FromHex("E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760"),
-                    mod_q, BigInteger.One));
+                    mod_q, BigInteger.One, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -268,7 +268,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                     mod_p,
                     FromHex("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C"),
                     FromHex("687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116"),
-                    mod_q, BigInteger.One));
+                    mod_q, BigInteger.One, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -303,7 +303,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                     mod_p,
                     FromHex("DC9203E514A721875485A529D2C722FB187BC8980EB866644DE41C68E143064546E861C0E2C9EDD92ADE71F46FCF50FF2AD97F951FDA9F2A2EB6546F39689BD3"),
                     FromHex("B4C4EE28CEBC6C2C8AC12952CF37F16AC7EFB6A9F69F4B57FFDA2E4F0DE5ADE038CBC2FFF719D2C18DE0284B8BFEF3B52B8CC7A5F5BF0A3C8D2319A5312557E1"),
-                    mod_q, BigInteger.Four));
+                    mod_q, BigInteger.Four, true));
             }
 
             protected override X9ECParameters CreateParameters()
diff --git a/crypto/src/asn1/gm/GMNamedCurves.cs b/crypto/src/asn1/gm/GMNamedCurves.cs
index 9cb2cef14..f906a2b95 100644
--- a/crypto/src/asn1/gm/GMNamedCurves.cs
+++ b/crypto/src/asn1/gm/GMNamedCurves.cs
@@ -52,7 +52,7 @@ namespace Org.BouncyCastle.Asn1.GM
                 BigInteger n = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123");
                 BigInteger h = BigInteger.One;
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -85,7 +85,7 @@ namespace Org.BouncyCastle.Asn1.GM
                 BigInteger n = FromHex("BDB6F4FE3E8B1D9E0DA8C0D40FC962195DFAE76F56564677");
                 BigInteger h = BigInteger.One;
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
diff --git a/crypto/src/asn1/sec/SECNamedCurves.cs b/crypto/src/asn1/sec/SECNamedCurves.cs
index 68e9b7eca..ad2f3e333 100644
--- a/crypto/src/asn1/sec/SECNamedCurves.cs
+++ b/crypto/src/asn1/sec/SECNamedCurves.cs
@@ -60,7 +60,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("DB7C2ABF62E35E7628DFAC6561C5");
                 BigInteger h = BigInteger.One;
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -94,7 +94,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("36DF0AAFD8B8D7597CA10520D04B");
                 BigInteger h = BigInteger.ValueOf(4);
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -128,7 +128,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("FFFFFFFE0000000075A30D1B9038A115");
                 BigInteger h = BigInteger.One;
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -162,7 +162,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3");
                 BigInteger h = BigInteger.ValueOf(4);
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -210,7 +210,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                         new BigInteger("96341f1138933bc2f503fd44", 16),
                         176));
 
-                return ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
+                return ConfigureCurveGlv(new FpCurve(p, a, b, n, h, true), glv);
             }
 
             protected override X9ECParameters CreateParameters()
@@ -244,7 +244,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("0100000000000000000001F4C8F927AED3CA752257");
                 BigInteger h = BigInteger.One;
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -278,7 +278,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("0100000000000000000000351EE786A818F3A1A16B");
                 BigInteger h = BigInteger.One;
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -326,7 +326,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                         new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16),
                         208));
 
-                return ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
+                return ConfigureCurveGlv(new FpCurve(p, a, b, n, h, true), glv);
             }
 
             protected override X9ECParameters CreateParameters()
@@ -360,7 +360,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831");
                 BigInteger h = BigInteger.One;
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -408,7 +408,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                         new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16),
                         240));
 
-                return ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
+                return ConfigureCurveGlv(new FpCurve(p, a, b, n, h, true), glv);
             }
 
             protected override X9ECParameters CreateParameters()
@@ -442,7 +442,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D");
                 BigInteger h = BigInteger.One;
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -490,7 +490,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                         new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16),
                         272));
 
-                return ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
+                return ConfigureCurveGlv(new FpCurve(p, a, b, n, h, true), glv);
             }
 
             protected override X9ECParameters CreateParameters()
@@ -524,7 +524,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
                 BigInteger h = BigInteger.One;
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -558,7 +558,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973");
                 BigInteger h = BigInteger.One;
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -593,7 +593,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409");
                 BigInteger h = BigInteger.One;
 
-                return ConfigureCurve(new FpCurve(p, a, b, n, h));
+                return ConfigureCurve(new FpCurve(p, a, b, n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
diff --git a/crypto/src/asn1/x9/X962NamedCurves.cs b/crypto/src/asn1/x9/X962NamedCurves.cs
index 04f3d335a..4fd3c8d1e 100644
--- a/crypto/src/asn1/x9/X962NamedCurves.cs
+++ b/crypto/src/asn1/x9/X962NamedCurves.cs
@@ -52,7 +52,7 @@ namespace Org.BouncyCastle.Asn1.X9
                     FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"),
                     FromHex("fffffffffffffffffffffffffffffffefffffffffffffffc"),
                     FromHex("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1"),
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -83,7 +83,7 @@ namespace Org.BouncyCastle.Asn1.X9
                     FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"),
                     FromHex("fffffffffffffffffffffffffffffffefffffffffffffffc"),
                     FromHex("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953"),
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -114,7 +114,7 @@ namespace Org.BouncyCastle.Asn1.X9
                     FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"),
                     FromHex("fffffffffffffffffffffffffffffffefffffffffffffffc"),
                     FromHex("22123dc2395a05caa7423daeccc94760a7d462256bd56916"),
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -145,7 +145,7 @@ namespace Org.BouncyCastle.Asn1.X9
                     new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
                     FromHex("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc"),
                     FromHex("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a"),
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -176,7 +176,7 @@ namespace Org.BouncyCastle.Asn1.X9
                     new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
                     FromHex("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc"),
                     FromHex("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c"),
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -207,7 +207,7 @@ namespace Org.BouncyCastle.Asn1.X9
                     new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
                     FromHex("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc"),
                     FromHex("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e"),
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -238,7 +238,7 @@ namespace Org.BouncyCastle.Asn1.X9
                     new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"),
                     FromHex("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc"),
                     FromHex("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"),
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
diff --git a/crypto/src/crypto/parameters/RsaKeyParameters.cs b/crypto/src/crypto/parameters/RsaKeyParameters.cs
index 48ea0ab5b..b1e1a8edf 100644
--- a/crypto/src/crypto/parameters/RsaKeyParameters.cs
+++ b/crypto/src/crypto/parameters/RsaKeyParameters.cs
@@ -2,6 +2,7 @@ using System;
 
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Parameters
 {
@@ -23,6 +24,14 @@ namespace Org.BouncyCastle.Crypto.Parameters
             if (!modulus.Gcd(SmallPrimesProduct).Equals(BigInteger.One))
                 throw new ArgumentException("RSA modulus has a small prime factor");
 
+            int maxBitLength = AsInteger("Org.BouncyCastle.Rsa.MaxSize", 15360);
+
+            int modBitLength = modulus.BitLength;
+            if (maxBitLength < modBitLength)
+            {
+                throw new ArgumentException("modulus value out of range");
+            }
+        
             // TODO: add additional primePower/Composite test - expensive!!
 
             return modulus;
@@ -81,5 +90,17 @@ namespace Org.BouncyCastle.Crypto.Parameters
         {
             return modulus.GetHashCode() ^ exponent.GetHashCode() ^ IsPrivate.GetHashCode();
         }
+
+        int AsInteger(string envVariable, int defaultValue)
+        {
+            String v = Platform.GetEnvironmentVariable(envVariable);
+
+            if (v == null)
+            {
+                return defaultValue;
+            }
+
+            return Int32.Parse(v);
+        }
     }
 }
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index f011b1baf..2b193ba06 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -677,6 +677,9 @@ namespace Org.BouncyCastle.Math.EC
     {
         private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
 
+        private static readonly IDictionary knownQs = Platform.CreateHashtable();
+        private static readonly SecureRandom random = new SecureRandom();
+
         protected readonly BigInteger m_q, m_r;
         protected readonly FpPoint m_infinity;
 
@@ -687,9 +690,42 @@ namespace Org.BouncyCastle.Math.EC
         }
 
         public FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)
+            : this(q, a, b, order, cofactor, false)
+        {
+        }
+
+        internal FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor, bool isInternal)
             : base(q)
         {
-            this.m_q = q;
+            if (isInternal)
+            {
+                this.m_q = q;
+                knownQs.add(q);
+            }
+            else if (knownQs.contains(q))
+            {
+                this.m_q = q;
+            }
+            else
+            {
+                int maxBitLength = AsInteger("Org.BouncyCastle.EC.Fp_MaxSize", 1042); // 2 * 521
+                int certainty = AsInteger("Org.BouncyCastle.EC.Fp_Certainty", 100);
+
+                int qBitLength = q.BitLength;
+                if (maxBitLength < qBitLength)
+                {
+                    throw new ArgumentException("Fp q value out of range");
+                }
+
+                if (Primes.HasAnySmallFactors(q) || !Primes.IsMRProbablePrime(
+                    q, random, getNumberOfIterations(qBitLength, certainty)))
+                {
+                    throw new ArgumentException("Fp q value not prime");
+                }
+
+                this.m_q = q;
+            }
+
             this.m_r = FpFieldElement.CalculateResidue(q);
             this.m_infinity = new FpPoint(this, null, null, false);
 
@@ -790,6 +826,50 @@ namespace Org.BouncyCastle.Math.EC
 
             return base.ImportPoint(p);
         }
+
+        private int GetNumberOfIterations(int bits, int certainty)
+        {
+            /*
+             * NOTE: We enforce a minimum 'certainty' of 100 for bits >= 1024 (else 80). Where the
+             * certainty is higher than the FIPS 186-4 tables (C.2/C.3) cater to, extra iterations
+             * are added at the "worst case rate" for the excess.
+             */
+            if (bits >= 1536)
+            {
+                return  certainty <= 100 ? 3
+                    :   certainty <= 128 ? 4
+                    :   4 + (certainty - 128 + 1) / 2;
+            }
+            else if (bits >= 1024)
+            {
+                return  certainty <= 100 ? 4
+                    :   certainty <= 112 ? 5
+                    :   5 + (certainty - 112 + 1) / 2;
+            }
+            else if (bits >= 512)
+            {
+                return  certainty <= 80  ? 5
+                    :   certainty <= 100 ? 7
+                    :   7 + (certainty - 100 + 1) / 2;
+            }
+            else
+            {
+                return  certainty <= 80  ? 40
+                    :   40 + (certainty - 80 + 1) / 2;
+            }
+        }
+
+        int AsInteger(string envVariable, int defaultValue)
+        {
+            String v = Platform.GetEnvironmentVariable(envVariable);
+
+            if (v == null)
+            {
+                return defaultValue;
+            }
+
+            return Int32.Parse(v);
+        }
     }
 
     public abstract class AbstractF2mCurve