Merge pull request #1179 from reaperhulk/dsa-numbers-opaque-backend

DSA Opaque Keys for OpenSSL
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 8d167ab..b3396ea 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -31,6 +31,7 @@
 from cryptography.hazmat.backends.openssl.ciphers import (
     _AESCTRCipherContext, _CipherContext
 )
+from cryptography.hazmat.backends.openssl.cmac import _CMACContext
 from cryptography.hazmat.backends.openssl.dsa import (
     _DSAParameters, _DSAPrivateKey, _DSAPublicKey,
     _DSASignatureContext, _DSAVerificationContext
@@ -39,12 +40,14 @@
     _ECDSASignatureContext, _ECDSAVerificationContext,
     _EllipticCurvePrivateKey, _EllipticCurvePublicKey
 )
+from cryptography.hazmat.backends.openssl.hashes import _HashContext
+from cryptography.hazmat.backends.openssl.hmac import _HMACContext
 from cryptography.hazmat.backends.openssl.rsa import (
     _RSAPrivateKey, _RSAPublicKey, _RSASignatureContext,
     _RSAVerificationContext
 )
 from cryptography.hazmat.bindings.openssl.binding import Binding
-from cryptography.hazmat.primitives import hashes, interfaces
+from cryptography.hazmat.primitives import hashes
 from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
 from cryptography.hazmat.primitives.asymmetric.padding import (
     MGF1, OAEP, PKCS1v15, PSS
@@ -1026,19 +1029,25 @@
         Generate a new private key on the named curve.
         """
 
-        curve_nid = self._elliptic_curve_to_nid(curve)
+        if backend.elliptic_curve_supported(curve):
+            curve_nid = self._elliptic_curve_to_nid(curve)
 
-        ctx = self._lib.EC_KEY_new_by_curve_name(curve_nid)
-        assert ctx != self._ffi.NULL
-        ctx = self._ffi.gc(ctx, self._lib.EC_KEY_free)
+            ctx = self._lib.EC_KEY_new_by_curve_name(curve_nid)
+            assert ctx != self._ffi.NULL
+            ctx = self._ffi.gc(ctx, self._lib.EC_KEY_free)
 
-        res = self._lib.EC_KEY_generate_key(ctx)
-        assert res == 1
+            res = self._lib.EC_KEY_generate_key(ctx)
+            assert res == 1
 
-        res = self._lib.EC_KEY_check_key(ctx)
-        assert res == 1
+            res = self._lib.EC_KEY_check_key(ctx)
+            assert res == 1
 
-        return _EllipticCurvePrivateKey(self, ctx, curve)
+            return _EllipticCurvePrivateKey(self, ctx, curve)
+        else:
+            raise UnsupportedAlgorithm(
+                "Backend object does not support {0}.".format(curve.name),
+                _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+            )
 
     def elliptic_curve_private_key_from_numbers(self, numbers):
         ec_key = self._ec_key_cdata_from_private_numbers(numbers)
@@ -1204,175 +1213,4 @@
         return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii"))
 
 
-@utils.register_interface(interfaces.HashContext)
-class _HashContext(object):
-    def __init__(self, backend, algorithm, ctx=None):
-        self.algorithm = algorithm
-
-        self._backend = backend
-
-        if ctx is None:
-            ctx = self._backend._lib.EVP_MD_CTX_create()
-            ctx = self._backend._ffi.gc(ctx,
-                                        self._backend._lib.EVP_MD_CTX_destroy)
-            evp_md = self._backend._lib.EVP_get_digestbyname(
-                algorithm.name.encode("ascii"))
-            if evp_md == self._backend._ffi.NULL:
-                raise UnsupportedAlgorithm(
-                    "{0} is not a supported hash on this backend.".format(
-                        algorithm.name),
-                    _Reasons.UNSUPPORTED_HASH
-                )
-            res = self._backend._lib.EVP_DigestInit_ex(ctx, evp_md,
-                                                       self._backend._ffi.NULL)
-            assert res != 0
-
-        self._ctx = ctx
-
-    def copy(self):
-        copied_ctx = self._backend._lib.EVP_MD_CTX_create()
-        copied_ctx = self._backend._ffi.gc(
-            copied_ctx, self._backend._lib.EVP_MD_CTX_destroy
-        )
-        res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx)
-        assert res != 0
-        return _HashContext(self._backend, self.algorithm, ctx=copied_ctx)
-
-    def update(self, data):
-        res = self._backend._lib.EVP_DigestUpdate(self._ctx, data, len(data))
-        assert res != 0
-
-    def finalize(self):
-        buf = self._backend._ffi.new("unsigned char[]",
-                                     self._backend._lib.EVP_MAX_MD_SIZE)
-        outlen = self._backend._ffi.new("unsigned int *")
-        res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen)
-        assert res != 0
-        assert outlen[0] == self.algorithm.digest_size
-        res = self._backend._lib.EVP_MD_CTX_cleanup(self._ctx)
-        assert res == 1
-        return self._backend._ffi.buffer(buf)[:outlen[0]]
-
-
-@utils.register_interface(interfaces.HashContext)
-class _HMACContext(object):
-    def __init__(self, backend, key, algorithm, ctx=None):
-        self.algorithm = algorithm
-        self._backend = backend
-
-        if ctx is None:
-            ctx = self._backend._ffi.new("HMAC_CTX *")
-            self._backend._lib.HMAC_CTX_init(ctx)
-            ctx = self._backend._ffi.gc(
-                ctx, self._backend._lib.HMAC_CTX_cleanup
-            )
-            evp_md = self._backend._lib.EVP_get_digestbyname(
-                algorithm.name.encode('ascii'))
-            if evp_md == self._backend._ffi.NULL:
-                raise UnsupportedAlgorithm(
-                    "{0} is not a supported hash on this backend.".format(
-                        algorithm.name),
-                    _Reasons.UNSUPPORTED_HASH
-                )
-            res = self._backend._lib.Cryptography_HMAC_Init_ex(
-                ctx, key, len(key), evp_md, self._backend._ffi.NULL
-            )
-            assert res != 0
-
-        self._ctx = ctx
-        self._key = key
-
-    def copy(self):
-        copied_ctx = self._backend._ffi.new("HMAC_CTX *")
-        self._backend._lib.HMAC_CTX_init(copied_ctx)
-        copied_ctx = self._backend._ffi.gc(
-            copied_ctx, self._backend._lib.HMAC_CTX_cleanup
-        )
-        res = self._backend._lib.Cryptography_HMAC_CTX_copy(
-            copied_ctx, self._ctx
-        )
-        assert res != 0
-        return _HMACContext(
-            self._backend, self._key, self.algorithm, ctx=copied_ctx
-        )
-
-    def update(self, data):
-        res = self._backend._lib.Cryptography_HMAC_Update(
-            self._ctx, data, len(data)
-        )
-        assert res != 0
-
-    def finalize(self):
-        buf = self._backend._ffi.new("unsigned char[]",
-                                     self._backend._lib.EVP_MAX_MD_SIZE)
-        outlen = self._backend._ffi.new("unsigned int *")
-        res = self._backend._lib.Cryptography_HMAC_Final(
-            self._ctx, buf, outlen
-        )
-        assert res != 0
-        assert outlen[0] == self.algorithm.digest_size
-        self._backend._lib.HMAC_CTX_cleanup(self._ctx)
-        return self._backend._ffi.buffer(buf)[:outlen[0]]
-
-
-@utils.register_interface(interfaces.CMACContext)
-class _CMACContext(object):
-    def __init__(self, backend, algorithm, ctx=None):
-        if not backend.cmac_algorithm_supported(algorithm):
-            raise UnsupportedAlgorithm("This backend does not support CMAC.",
-                                       _Reasons.UNSUPPORTED_CIPHER)
-
-        self._backend = backend
-        self._key = algorithm.key
-        self._algorithm = algorithm
-        self._output_length = algorithm.block_size // 8
-
-        if ctx is None:
-            registry = self._backend._cipher_registry
-            adapter = registry[type(algorithm), CBC]
-
-            evp_cipher = adapter(self._backend, algorithm, CBC)
-
-            ctx = self._backend._lib.CMAC_CTX_new()
-
-            assert ctx != self._backend._ffi.NULL
-            ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free)
-
-            self._backend._lib.CMAC_Init(
-                ctx, self._key, len(self._key),
-                evp_cipher, self._backend._ffi.NULL
-            )
-
-        self._ctx = ctx
-
-    def update(self, data):
-        res = self._backend._lib.CMAC_Update(self._ctx, data, len(data))
-        assert res == 1
-
-    def finalize(self):
-        buf = self._backend._ffi.new("unsigned char[]", self._output_length)
-        length = self._backend._ffi.new("size_t *", self._output_length)
-        res = self._backend._lib.CMAC_Final(
-            self._ctx, buf, length
-        )
-        assert res == 1
-
-        self._ctx = None
-
-        return self._backend._ffi.buffer(buf)[:]
-
-    def copy(self):
-        copied_ctx = self._backend._lib.CMAC_CTX_new()
-        copied_ctx = self._backend._ffi.gc(
-            copied_ctx, self._backend._lib.CMAC_CTX_free
-        )
-        res = self._backend._lib.CMAC_CTX_copy(
-            copied_ctx, self._ctx
-        )
-        assert res == 1
-        return _CMACContext(
-            self._backend, self._algorithm, ctx=copied_ctx
-        )
-
-
 backend = Backend()
diff --git a/cryptography/hazmat/backends/openssl/cmac.py b/cryptography/hazmat/backends/openssl/cmac.py
new file mode 100644
index 0000000..7acf439
--- /dev/null
+++ b/cryptography/hazmat/backends/openssl/cmac.py
@@ -0,0 +1,80 @@
+# 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.
+
+from __future__ import absolute_import, division, print_function
+
+
+from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.primitives import interfaces
+from cryptography.hazmat.primitives.ciphers.modes import CBC
+
+
+@utils.register_interface(interfaces.CMACContext)
+class _CMACContext(object):
+    def __init__(self, backend, algorithm, ctx=None):
+        if not backend.cmac_algorithm_supported(algorithm):
+            raise UnsupportedAlgorithm("This backend does not support CMAC.",
+                                       _Reasons.UNSUPPORTED_CIPHER)
+
+        self._backend = backend
+        self._key = algorithm.key
+        self._algorithm = algorithm
+        self._output_length = algorithm.block_size // 8
+
+        if ctx is None:
+            registry = self._backend._cipher_registry
+            adapter = registry[type(algorithm), CBC]
+
+            evp_cipher = adapter(self._backend, algorithm, CBC)
+
+            ctx = self._backend._lib.CMAC_CTX_new()
+
+            assert ctx != self._backend._ffi.NULL
+            ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free)
+
+            self._backend._lib.CMAC_Init(
+                ctx, self._key, len(self._key),
+                evp_cipher, self._backend._ffi.NULL
+            )
+
+        self._ctx = ctx
+
+    def update(self, data):
+        res = self._backend._lib.CMAC_Update(self._ctx, data, len(data))
+        assert res == 1
+
+    def finalize(self):
+        buf = self._backend._ffi.new("unsigned char[]", self._output_length)
+        length = self._backend._ffi.new("size_t *", self._output_length)
+        res = self._backend._lib.CMAC_Final(
+            self._ctx, buf, length
+        )
+        assert res == 1
+
+        self._ctx = None
+
+        return self._backend._ffi.buffer(buf)[:]
+
+    def copy(self):
+        copied_ctx = self._backend._lib.CMAC_CTX_new()
+        copied_ctx = self._backend._ffi.gc(
+            copied_ctx, self._backend._lib.CMAC_CTX_free
+        )
+        res = self._backend._lib.CMAC_CTX_copy(
+            copied_ctx, self._ctx
+        )
+        assert res == 1
+        return _CMACContext(
+            self._backend, self._algorithm, ctx=copied_ctx
+        )
diff --git a/cryptography/hazmat/backends/openssl/hashes.py b/cryptography/hazmat/backends/openssl/hashes.py
new file mode 100644
index 0000000..da91eef
--- /dev/null
+++ b/cryptography/hazmat/backends/openssl/hashes.py
@@ -0,0 +1,69 @@
+# 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.
+
+from __future__ import absolute_import, division, print_function
+
+
+from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.primitives import interfaces
+
+
+@utils.register_interface(interfaces.HashContext)
+class _HashContext(object):
+    def __init__(self, backend, algorithm, ctx=None):
+        self.algorithm = algorithm
+
+        self._backend = backend
+
+        if ctx is None:
+            ctx = self._backend._lib.EVP_MD_CTX_create()
+            ctx = self._backend._ffi.gc(ctx,
+                                        self._backend._lib.EVP_MD_CTX_destroy)
+            evp_md = self._backend._lib.EVP_get_digestbyname(
+                algorithm.name.encode("ascii"))
+            if evp_md == self._backend._ffi.NULL:
+                raise UnsupportedAlgorithm(
+                    "{0} is not a supported hash on this backend.".format(
+                        algorithm.name),
+                    _Reasons.UNSUPPORTED_HASH
+                )
+            res = self._backend._lib.EVP_DigestInit_ex(ctx, evp_md,
+                                                       self._backend._ffi.NULL)
+            assert res != 0
+
+        self._ctx = ctx
+
+    def copy(self):
+        copied_ctx = self._backend._lib.EVP_MD_CTX_create()
+        copied_ctx = self._backend._ffi.gc(
+            copied_ctx, self._backend._lib.EVP_MD_CTX_destroy
+        )
+        res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx)
+        assert res != 0
+        return _HashContext(self._backend, self.algorithm, ctx=copied_ctx)
+
+    def update(self, data):
+        res = self._backend._lib.EVP_DigestUpdate(self._ctx, data, len(data))
+        assert res != 0
+
+    def finalize(self):
+        buf = self._backend._ffi.new("unsigned char[]",
+                                     self._backend._lib.EVP_MAX_MD_SIZE)
+        outlen = self._backend._ffi.new("unsigned int *")
+        res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen)
+        assert res != 0
+        assert outlen[0] == self.algorithm.digest_size
+        res = self._backend._lib.EVP_MD_CTX_cleanup(self._ctx)
+        assert res == 1
+        return self._backend._ffi.buffer(buf)[:outlen[0]]
diff --git a/cryptography/hazmat/backends/openssl/hmac.py b/cryptography/hazmat/backends/openssl/hmac.py
new file mode 100644
index 0000000..3f1576f
--- /dev/null
+++ b/cryptography/hazmat/backends/openssl/hmac.py
@@ -0,0 +1,80 @@
+# 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.
+
+from __future__ import absolute_import, division, print_function
+
+
+from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.primitives import interfaces
+
+
+@utils.register_interface(interfaces.HashContext)
+class _HMACContext(object):
+    def __init__(self, backend, key, algorithm, ctx=None):
+        self.algorithm = algorithm
+        self._backend = backend
+
+        if ctx is None:
+            ctx = self._backend._ffi.new("HMAC_CTX *")
+            self._backend._lib.HMAC_CTX_init(ctx)
+            ctx = self._backend._ffi.gc(
+                ctx, self._backend._lib.HMAC_CTX_cleanup
+            )
+            evp_md = self._backend._lib.EVP_get_digestbyname(
+                algorithm.name.encode('ascii'))
+            if evp_md == self._backend._ffi.NULL:
+                raise UnsupportedAlgorithm(
+                    "{0} is not a supported hash on this backend.".format(
+                        algorithm.name),
+                    _Reasons.UNSUPPORTED_HASH
+                )
+            res = self._backend._lib.Cryptography_HMAC_Init_ex(
+                ctx, key, len(key), evp_md, self._backend._ffi.NULL
+            )
+            assert res != 0
+
+        self._ctx = ctx
+        self._key = key
+
+    def copy(self):
+        copied_ctx = self._backend._ffi.new("HMAC_CTX *")
+        self._backend._lib.HMAC_CTX_init(copied_ctx)
+        copied_ctx = self._backend._ffi.gc(
+            copied_ctx, self._backend._lib.HMAC_CTX_cleanup
+        )
+        res = self._backend._lib.Cryptography_HMAC_CTX_copy(
+            copied_ctx, self._ctx
+        )
+        assert res != 0
+        return _HMACContext(
+            self._backend, self._key, self.algorithm, ctx=copied_ctx
+        )
+
+    def update(self, data):
+        res = self._backend._lib.Cryptography_HMAC_Update(
+            self._ctx, data, len(data)
+        )
+        assert res != 0
+
+    def finalize(self):
+        buf = self._backend._ffi.new("unsigned char[]",
+                                     self._backend._lib.EVP_MAX_MD_SIZE)
+        outlen = self._backend._ffi.new("unsigned int *")
+        res = self._backend._lib.Cryptography_HMAC_Final(
+            self._ctx, buf, outlen
+        )
+        assert res != 0
+        assert outlen[0] == self.algorithm.digest_size
+        self._backend._lib.HMAC_CTX_cleanup(self._ctx)
+        return self._backend._ffi.buffer(buf)[:outlen[0]]
diff --git a/cryptography/hazmat/backends/openssl/rsa.py b/cryptography/hazmat/backends/openssl/rsa.py
index 2fada1b..a62a89f 100644
--- a/cryptography/hazmat/backends/openssl/rsa.py
+++ b/cryptography/hazmat/backends/openssl/rsa.py
@@ -422,7 +422,11 @@
         assert res == 1
         self._evp_pkey = evp_pkey
 
-        self.key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
+        self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
+
+    @property
+    def key_size(self):
+        return self._key_size
 
     def signer(self, padding, algorithm):
         return _RSASignatureContext(self._backend, self, padding, algorithm)
@@ -474,7 +478,11 @@
         assert res == 1
         self._evp_pkey = evp_pkey
 
-        self.key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
+        self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
+
+    @property
+    def key_size(self):
+        return self._key_size
 
     def verifier(self, signature, padding, algorithm):
         return _RSAVerificationContext(
diff --git a/docs/development/getting-started.rst b/docs/development/getting-started.rst
index 4337b47..f5d6c19 100644
--- a/docs/development/getting-started.rst
+++ b/docs/development/getting-started.rst
@@ -2,10 +2,10 @@
 ===============
 
 Working on ``cryptography`` requires the installation of a small number of
-development dependencies in addition to the dependencies for :doc:`/installation`.
-These are listed in ``dev-requirements.txt`` and they can be installed in a
-`virtualenv`_ using `pip`_. Once you've installed the dependencies, install
-``cryptography`` in ``editable`` mode. For example:
+development dependencies in addition to the dependencies for
+:doc:`/installation`. These are listed in ``dev-requirements.txt`` and they can
+be installed in a `virtualenv`_ using `pip`_. Once you've installed the
+dependencies, install ``cryptography`` in ``editable`` mode. For example:
 
 .. code-block:: console
 
@@ -13,6 +13,9 @@
     $ pip install --requirement dev-requirements.txt
     $ pip install --editable .
 
+You will also need to install ``enchant`` using your system's package manager
+to check spelling in the documentation.
+
 You are now ready to run the tests and build the documentation.
 
 Running tests
diff --git a/docs/hazmat/primitives/asymmetric/ec.rst b/docs/hazmat/primitives/asymmetric/ec.rst
index 5dc7e2f..4b3c460 100644
--- a/docs/hazmat/primitives/asymmetric/ec.rst
+++ b/docs/hazmat/primitives/asymmetric/ec.rst
@@ -116,7 +116,7 @@
         >>> from cryptography.hazmat.primitives import hashes
         >>> from cryptography.hazmat.primitives.asymmetric import ec
         >>> private_key = ec.generate_private_key(
-        ...     ec.SECT283K1(), default_backend()
+        ...     ec.SECP384R1(), default_backend()
         ... )
         >>> signer = private_key.signer(ec.ECDSA(hashes.SHA256()))
         >>> signer.update(b"this is some data I'd like")
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index bcb1fb3..abc2b07 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -430,9 +430,9 @@
     make a message the correct size. ``CipherContext`` will not automatically
     apply any padding; you'll need to add your own. For block ciphers the
     recommended padding is
-    :class:`cryptography.hazmat.primitives.padding.PKCS7`. If you are using a
+    :class:`~cryptography.hazmat.primitives.padding.PKCS7`. If you are using a
     stream cipher mode (such as
-    :class:`cryptography.hazmat.primitives.modes.CTR`) you don't have to worry
+    :class:`~cryptography.hazmat.primitives.modes.CTR`) you don't have to worry
     about this.
 
     .. method:: update(data)
@@ -443,7 +443,7 @@
 
         When the ``Cipher`` was constructed in a mode that turns it into a
         stream cipher (e.g.
-        :class:`cryptography.hazmat.primitives.ciphers.modes.CTR`), this will
+        :class:`~cryptography.hazmat.primitives.ciphers.modes.CTR`), this will
         return bytes immediately, however in other modes it will return chunks
         whose size is determined by the cipher's block size.
 
diff --git a/docs/limitations.rst b/docs/limitations.rst
index 5b63ef5..ce61d89 100644
--- a/docs/limitations.rst
+++ b/docs/limitations.rst
@@ -10,10 +10,10 @@
 uninitialized memory.
 
 Python exposes no API for us to implement this reliably and as such almost all
-software in Python is potentially vulnerable to this attack. However the
-`CERT secure coding guidelines`_ consider this issue as "low severity,
-unlikely, expensive to repair" and we do not consider this a high risk for most
-users.
+software in Python is potentially vulnerable to this attack. The
+`CERT secure coding guidelines`_ assesses this issue as "Severity: medium,
+Likelihood: unlikely, Remediation Cost: expensive to repair" and we do not
+consider this a high risk for most users.
 
 .. _`Memory wiping`:  http://blogs.msdn.com/b/oldnewthing/archive/2013/05/29/10421912.aspx
 .. _`CERT secure coding guidelines`: https://www.securecoding.cert.org/confluence/display/seccode/MEM03-C.+Clear+sensitive+information+stored+in+reusable+resources