Synopse Open Source - Tag - CSPRNGmORMot MVC / SOA / ORM and friends2024-02-02T17:08:25+00:00urn:md5:cc547126eb580a9adbec2349d7c65274DotclearNative X.509, RSA and HSM Supporturn:md5:6404121d596d3c5cee045e29cf93e02b2023-12-09T11:01:00+00:002023-12-10T18:13:06+00:00Arnaud BouchezmORMot FrameworkAsymmetricCrossPlatformCSPRNGDelphiECCed25519forensicFPCFreePascalGoodPracticeinterfacemORMotmORMot2OpenSourceOpenSSLperformancePKCS11RSAsecurityX509<p>Today, almost all computer security relies on asymmetric cryptography and X.509 certificates as file or hardware modules.<br />
And the RSA algorithm is still used to sign the vast majority of those certificates. Even if there are better options (like ECC-256), RSA-2048 seems the actual standard, at least still allowed for a few years.</p>
<p><img src="https://blog.synopse.info?post/public/blog/mormotSecurity.jpg" alt="" /></p>
<p>So we added pure pascal RSA cryptography and X.509 certificates support in <em>mORMot</em>.<br />
Last but not least, we also added Hardware Security Modules support via the PKCS#11 standard.<br />
Until now, we were mostly relying on OpenSSL, but a native embedded solution would be smaller in code size, better for reducing dependencies, and easier to work with (especially for HSM). The main idea is to offer only safe algorithms and methods, so that you can write reliable software, even if you are no cryptographic expert. <img src="https://blog.synopse.info?pf=smile.svg" alt=":)" class="smiley" /></p> <h4>Rivest-Shamir-Adleman (RSA) Public-Key Cryptography</h4>
<p>The RSA public-key algorithm was designed back in 1977, and is still the most widely used. In order to fully implement it, we need to generate new key pairs (public and private keys), then sign and verify (or encrypt or decrypt) data with the key. For instance, a private key is kept secret, and used for an Authority to sign a certificate, and the public key is published, and able to verify a certificate. It is based on large prime numbers, so we needed to develop a Big Integer library, which is not part of Delphi or FPC RTL.</p>
<p><img src="https://blog.synopse.info?post/public/blog/RSAalgo.png" alt="" /></p>
<p>Here as some notes about our implementation in <a href="https://github.com/synopse/mORMot2/blob/master/src/crypt/mormot.crypt.rsa.pas">mormot.crypt.rsa.pas</a>:</p>
<ul>
<li>new pure pascal OOP design of BigInt computation optimized for RSA process;</li>
<li>dedicated x86_64/i386 asm for core computation routines (noticeable speedup);</li>
<li>use half-registers (HalfUInt) for efficient computation on all CPUs (arm and aarch64 numbers are good);</li>
<li>slower than OpenSSL, but likely to be the fastest FPC or Delphi native RSA library, thanks to our optimized asm: for instance, you can generate a new RSA-2048 keypair in less than a second;</li>
<li>internal garbage collection of BigInt instances, to minimize heap pressure during computation, and ensure all values are wiped once used during the process - as proven anti-forensic measure;</li>
<li>includes FIPS-level RSA keypair validation and generation, using a safe random source, with efficient prime number detection, and minimal code size;</li>
<li>features both RSASSA-PKCS1-v1_5 and RSASSA-PSS signature schemes;</li>
<li>started as a fcl-hash fork, but full rewrite inspired by Mbed TLS source because this initial code is slow and incomplete;</li>
<li>references: we followed <a href="https://github.com/Mbed-TLS/mbedtls">the Mbded TLS</a> implementation (which is much easier to follow than OpenSSL), and the well known <a href="https://cacr.uwaterloo.ca/hac/about/chap4.pdf">Handbook of Applied Cryptography (HAC)</a> recommendations;</li>
<li>includes full coverage of unit tests to avoid any regression, validated against the OpenSSL library as audited reference;</li>
<li>this unit will register as <code>Asym</code> 'RS256','RS384','RS512' algorithms (if not overridden by the faster <code>mormot.crypt.openssl</code>), keeping 'RS256-int' and 'PS256-int' available to use our unit;</li>
<li>as used by <code>mormot.crypt.x509</code> (see below) to handle RSA signatures of its X.509 Certificates.</li>
</ul>
<p>For instance, if you want to access a <code>TCryptAsym</code> digital signature instance with RSA-2048 and SHA-256 hashing, you can just use the <code>CryptAsym</code> global variable with <code>caaRS256</code> algorithm as factory.<br />
If you need just public/private key support, you can use <code>CryptPublicKey</code> or <code>CryptPrivateKey</code> factories with <code>ckaRsa</code> algorithm.</p>
<p>About RSA security:</p>
<ul>
<li>RSA-512 or RSA-1024 are considered unsafe and should not be used.</li>
<li>RSA-2048 confers 112-bit of security, and is the usual choice today when this algorithm is to be used.</li>
<li>RSA-3072 could confer 128-bit of security, at the expense of being slower and 50% bigger - so switching to ECC-256 may be a better option, for the same level of security.</li>
<li>RSA-4096 is not worth it in respect to RSA-3072, and RSA-7680 is very big and slow, and only gives 192-bit of security, so should be avoided.</li>
</ul>
<p>Anyway, our library is able to support all those key sizes, up to RSA-7680 is you really need it.<br />
See <a href="https://stackoverflow.com/a/589850/458259">this SO response</a> as reference about RSA keysizes.</p>
<h4>X.509 Certificates</h4>
<p>As we wrote in introduction, X.509 certificates are the base of most computer security.<br />
The whole TLS/HTTPS stack makes use of it, and the whole Internet would collapse without it.</p>
<p>We developed our <a href="https://github.com/synopse/mORMot2/blob/master/src/crypt/mormot.crypt.x509.pas">mormot.crypt.x509.pas</a> unit from scratch, featuring:</p>
<ul>
<li>X.509 Certificates Fields Logic (e.g. X.501 Type Names);</li>
<li>X.509 Certificates and Certificate Signing Request (CSR);</li>
<li>X509 Certificate Revocation List (CRL);</li>
<li>X509 Private Key Infrastructure (PKI);</li>
<li>Registration of our X.509 Engine to the <code>TCryptCert</code>/<code>TCryptStore</code> Factories.</li>
</ul>
<p><img src="https://blog.synopse.info?post/public/blog/X509certificate.png" alt="" /></p>
<p>The raw binary encoding is using the (weird) ASN.1 syntax, which is now implemented as part of the <a href="https://github.com/synopse/mORMot2/blob/master/src/crypt/mormot.crypt.secure.pas">mormot.crypt.secure.pas</a> unit.<br />
We followed the RFC 5280 specifications, and mapped latest X.509 Certificates / CSR / CRL extensions, with some low-level but very readable pascal code using classes, records and enumerates. It features perfect compatibility with our <code>ICryptCert</code> high-level interface wrappers, ready to be used in a very convenient way. We support all basic functions, but also advanced features like open/sealing or text peer information in a human readable format.<br />
When using our unit, your end-user code should not be lost within the complex details and notions of the X.509 format (like OIDs, versions or extensions), but use high-level pascal code, with no possibility to use a weak or invalid configuration.</p>
<p>Of course, it can support not only our new RSA keys, but also ECC-256 as implemented by our native <a href="https://github.com/synopse/mORMot2/blob/master/src/crypt/mormot.crypt.ecc.pas">mormot.crypt.ecc.pas</a>, or any other algorithm, e.g. available from OpenSSL.</p>
<h4>X.509 Private Key Infrastructure (PKI)</h4>
<p>Our unit features a full Private Key Infrastructure (PKI) implementation.<br />
In fact, X.509 certificates are as weak as the PKI they are used on. You can have strong certificates, but a weak verification pattern. In end-user applications, it is typical to see all the security being lost by a poor (e.g. naive) implementation of the keys interaction.</p>
<p><img src="https://blog.synopse.info?post/public/blog/PKI.png" alt="" /></p>
<p>This is why our unit publishes a 'x509-pki' <code>ICryptStore </code> as a full featured PKI:</p>
<ul>
<li>using our <code>TX509</code> and <code>TX509Crl</code> classes for actual certificates process;</li>
<li>clean verification of the chain of trust, with customized depth and proper root Certificate Authority (CA) support, following the RFC 5280 section 6 requirements of a clean "Certification Path Validation";</li>
<li>maintaining a cache of <code>ICryptCert</code> instances, which makes a huge performance benefit in the context of a PKI (e.g. you don't need to parse the X.509 binary, or verify the chain of trust each time).</li>
</ul>
<p>We tried to make performance and usability in the highest possible standards, to let you focus on your business logic, and keep the hard cryptography work done in the <em>mORMot</em> library code.</p>
<h4>Hardware Security Modules (HSM) via PKCS#11</h4>
<p>The PKCS#11 standard is a way to define some software access to Hardware Security Modules, via a set of defined API calls.<br />
We just published the <a href="https://github.com/synopse/mORMot2/blob/master/src/crypt/mormot.crypt.pkcs11.pas">mormot.crypt.pkcs11.pas</a> unit to interface those devices with the other <em>mORMot</em> PKI.</p>
<p><img src="https://blog.synopse.info?post/public/blog/HSM.png" alt="" /></p>
<p>Once you have loaded the library of your actual hardware (typically a <code>.dll</code> or <code>.so</code>) using a <code>TCryptCertAlgoPkcs11</code> instance, you can see all stored certificates and keys, as high-level regular <code>ICryptCert</code> instances, and sign or verify any kind of data (some binary or some other certificates), using the private key safely stored on in the hardware device.<br />
This is usually slower than a pure software verification, but it is much safer, because the private key is sealed within the hardware token, and never leave it. So it can't be intercepted and stolen.</p>
<h4>You are Welcome!</h4>
<p>With those <em>mORMot</em> cryptography units, you now have anything at hand to use standard and proven public-key cryptography in your applications, on both Delphi or FPC, with no external dll deployment issue, and minimal code size increase.<br />
We can thank a lot <a href="https://www.tranquil.it/en">my employer</a> for needing those nice features, therefore letting me work on them.<br />
Open Source rocks! :)</p>AES-256 based Cryptographically Secure Pseudo-Random Number Generator (CSPRNG)urn:md5:d99c0c7b643507d7c78be9a1b13ce23b2016-04-09T11:37:00+02:002020-07-03T09:29:59+02:00AB4327-GANDImORMot FrameworkAESAES-NiblogCSPRNGDelphiperformancerandomsecuritySource<p>Everyone knows about the pascal <a href="http://docwiki.embarcadero.com/Libraries/en/System.Random">random()
function</a>.<br />
It returns some numbers, using a <a href="http://en.wikipedia.org/wiki/Linear_congruential_generator">linear
congruential generator</a>, with a multiplier of <a href="http://forum.lazarus.freepascal.org/index.php?topic=23536.msg140722#msg140722">134775813</a>,
in its Delphi implementation.<br />
It is fast, but not really secure. Output is very predictable, especially if
you forgot to execute the <a href="http://docwiki.embarcadero.com/Libraries/en/System.RandSeed">RandSeed()
procedure</a>.</p>
<p><img src="http://resources.infosecinstitute.com/wp-content/uploads/121411_1611_SecureRando1.png" alt="" width="500" height="148" /></p>
<p>In real world scenarios, safety always requires random numbers, e.g. for
key/nonce/IV/salt/challenge generation.<br />
The less predictable, the better.<br />
We just included a <a href="https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator">Cryptographically
Secure Pseudo-Random Number Generator</a> (CSPRNG) into our <a href="https://github.com/synopse/mORMot/commit/92135fcdf7503bb54479643e926668532ca357d3">
SynCrypto.pas</a> unit.<br />
The <code>TAESPRNG</code> class would use real system entropy to generate
a sequence of pseudorandom bytes, using AES-256, so returning highly
unpredictable content.</p> <p>The <code>TAESPRNG</code> class is implemented as such:</p>
<ul>
<li>It would gather entropy using dedicated OS API, i.e. the <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa379942">CryptGenRandom
API</a> under Windows or <a href="http://www.2uo.de/myths-about-urandom/">/dev/urandom - /dev/random</a> on
Linux/POSIX systems; and since we are paranoid, we XOR some entropy hash
(retrieved e.g. directly from RDTSC and other system variables) to those OS
values - so even if the API is compromised, we try to have some changing
input;</li>
<li>This entropy (256 bytes of password, 16 bytes of salt) would be hashed
using safe PBKDF2-HMAC-SHA256 key derivation function (256 iterations by
default) to setup the secret key of an AES-256 cypher, and set a counter (CTR)
initial value by applying this AES-256 to the salt;</li>
<li>Each time some output is to be generated, AES-256 is applied to the CTR to
produce 16 bytes (2^128 bits) of pseudorandom data;</li>
<li>The CTR is incremented after each 16-byte block; AES being a block
cipher, it is a permutation of the space of block values: as such, it won't
ever output twice the same 16-byte block, so you can generate 2^128 blocks,
i.e. 2^132 bytes before the CTR overflows;</li>
<li>The AES-256 cypher is re-seeded from entropy on a regular basis (after
some bytes are generated), to avoid potential attacks on backward or
forward security;</li>
<li>The implementation is thread-safe, a shared <code>TAESPRNG.Main</code>
instance is available, but you can create your
own <code>TAESPRNG</code> instance, with tuned parameters (number
of PBKDF2 counts or automatic re-seeding number of bytes);</li>
<li>The level of security would be the same on all platforms, since OS is used
only for entropy, but an unique CSPRNG algorithm would actually generate
the data - even a compromised system (older CryptGenRandomAPI had <a href="http://eprint.iacr.org/2007/419.pdf">known weaknesses</a>, or you could
imagine some plot-based undocumented backdoor) may produce safe enough
output;</li>
<li>It would use <a href="https://blog.synopse.info?post/post/2015/01/15/AES-NI-enabled-for-SynCrypto">AES-NI</a> or Padlock hardware
acceleration, if available.</li>
</ul>
<p>You may use it in your projects by calling <a href="http://synopse.info/files/html/api-1.18/SynCrypto.html#TAESPRNG_FILLRANDOM">TAESPRNG.Main.FillRandom()</a>
overloaded methods or <a href="http://synopse.info/files/html/api-1.18/SynCrypto.html#TAESPRNG_FILLRANDOMBYTES">
TAESPRNG.Main.FillRandomBytes()</a>.</p>
<p>See the <a href="http://synopse.info/files/html/api-1.18/SynCrypto.html#TAESPRNG">class
documentation</a>.</p>
<p>The main idea of a CSPRNG is that its output is as safe as the cypher it is
based on.<br />
Using AES-256, and initial PBKDF2 key derivation of OS-gathered entropy,
implements a <a href="https://en.wikipedia.org/wiki/Randomness_extractor">very
good randomness extractor</a>.<br />
Last but not least, especially if your CPU supports AES-NI (which is very
likely on a server), performance would be very high.<br />
Just use <code>TAESPRNG</code> when you need random input. Then go back to
your own code.</p>
<p>Feedback is <a href="http://synopse.info/forum/viewtopic.php?id=3263">welcome on our forum</a>, as
usual!</p>