示例#1
0
            public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding)
            {
                ArgumentNullException.ThrowIfNull(data);
                ArgumentNullException.ThrowIfNull(padding);

                Interop.AndroidCrypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor? oaepProcessor);
                SafeRsaHandle key = GetKey();

                int         rsaSize     = Interop.AndroidCrypto.RsaSize(key);
                Span <byte> destination = default;

                byte[] buf = CryptoPool.Rent(rsaSize);

                try
                {
                    destination = new Span <byte>(buf, 0, rsaSize);

                    if (!TryDecrypt(key, data, destination, rsaPadding, oaepProcessor, out int bytesWritten))
                    {
                        Debug.Fail($"{nameof(TryDecrypt)} should not return false for RSA_size buffer");
                        throw new CryptographicException();
                    }

                    return(destination.Slice(0, bytesWritten).ToArray());
                }
                finally
                {
                    CryptographicOperations.ZeroMemory(destination);
                    CryptoPool.Return(buf, clearSize: 0);
                }
            }
示例#2
0
            public override byte[] Encrypt(byte[] data, RSAEncryptionPadding padding)
            {
                ArgumentNullException.ThrowIfNull(data);
                ArgumentNullException.ThrowIfNull(padding);

                Interop.AndroidCrypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor? oaepProcessor);
                SafeRsaHandle key = GetKey();

                byte[] buf = new byte[Interop.AndroidCrypto.RsaSize(key)];

                bool encrypted = TryEncrypt(
                    key,
                    data,
                    buf,
                    rsaPadding,
                    oaepProcessor,
                    out int bytesWritten);

                if (!encrypted || bytesWritten != buf.Length)
                {
                    Debug.Fail($"TryEncrypt behaved unexpectedly: {nameof(encrypted)}=={encrypted}, {nameof(bytesWritten)}=={bytesWritten}, {nameof(buf.Length)}=={buf.Length}");
                    throw new CryptographicException();
                }

                return(buf);
            }
示例#3
0
            private static bool TryDecrypt(
                SafeRsaHandle key,
                ReadOnlySpan <byte> data,
                Span <byte> destination,
                Interop.AndroidCrypto.RsaPadding rsaPadding,
                out int bytesWritten)
            {
                // Caller should have already checked this.
                Debug.Assert(!key.IsInvalid);

                int rsaSize = Interop.AndroidCrypto.RsaSize(key);

                if (data.Length != rsaSize)
                {
                    throw new CryptographicException(SR.Cryptography_RSA_DecryptWrongSize);
                }

                if (destination.Length < rsaSize)
                {
                    bytesWritten = 0;
                    return(false);
                }

                int returnValue = Interop.AndroidCrypto.RsaPrivateDecrypt(data.Length, data, destination, key, rsaPadding);

                CheckReturn(returnValue);
                bytesWritten = returnValue;
                return(true);
            }
示例#4
0
            public override bool TryEncrypt(ReadOnlySpan <byte> data, Span <byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
            {
                ArgumentNullException.ThrowIfNull(padding);

                Interop.AndroidCrypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor? oaepProcessor);
                SafeRsaHandle key = GetKey();

                return(TryEncrypt(key, data, destination, rsaPadding, oaepProcessor, out bytesWritten));
            }
示例#5
0
            private static bool TryEncrypt(
                SafeRsaHandle key,
                ReadOnlySpan <byte> data,
                Span <byte> destination,
                Interop.AndroidCrypto.RsaPadding rsaPadding,
                RsaPaddingProcessor?rsaPaddingProcessor,
                out int bytesWritten)
            {
                int rsaSize = Interop.AndroidCrypto.RsaSize(key);

                if (destination.Length < rsaSize)
                {
                    bytesWritten = 0;
                    return(false);
                }

                int returnValue;

                if (rsaPaddingProcessor != null)
                {
                    Debug.Assert(rsaPadding == Interop.AndroidCrypto.RsaPadding.NoPadding);
                    byte[]      rented = CryptoPool.Rent(rsaSize);
                    Span <byte> tmp    = new Span <byte>(rented, 0, rsaSize);

                    try
                    {
                        rsaPaddingProcessor.PadOaep(data, tmp);
                        returnValue = Interop.AndroidCrypto.RsaPublicEncrypt(tmp.Length, tmp, destination, key, rsaPadding);
                    }
                    finally
                    {
                        CryptographicOperations.ZeroMemory(tmp);
                        CryptoPool.Return(rented, clearSize: 0);
                    }
                }
                else
                {
                    Debug.Assert(rsaPadding != Interop.AndroidCrypto.RsaPadding.NoPadding);

                    returnValue = Interop.AndroidCrypto.RsaPublicEncrypt(data.Length, data, destination, key, rsaPadding);
                }

                CheckReturn(returnValue);

                bytesWritten = returnValue;
                Debug.Assert(returnValue == rsaSize, $"{returnValue} != {rsaSize}");
                return(true);
            }
示例#6
0
            private static bool TryEncrypt(
                SafeRsaHandle key,
                ReadOnlySpan <byte> data,
                Span <byte> destination,
                Interop.AndroidCrypto.RsaPadding rsaPadding,
                out int bytesWritten)
            {
                int rsaSize = Interop.AndroidCrypto.RsaSize(key);

                if (destination.Length < rsaSize)
                {
                    bytesWritten = 0;
                    return(false);
                }

                int returnValue = Interop.AndroidCrypto.RsaPublicEncrypt(data.Length, data, destination, key, rsaPadding);

                CheckReturn(returnValue);
                bytesWritten = returnValue;
                Debug.Assert(returnValue == rsaSize, $"{returnValue} != {rsaSize}");
                return(true);
            }
示例#7
0
            private static bool TryDecrypt(
                SafeRsaHandle key,
                ReadOnlySpan <byte> data,
                Span <byte> destination,
                Interop.AndroidCrypto.RsaPadding rsaPadding,
                RsaPaddingProcessor?rsaPaddingProcessor,
                out int bytesWritten)
            {
                // If rsaPadding is PKCS1 or OAEP-SHA1 then no depadding method should be present.
                // If rsaPadding is NoPadding then a depadding method should be present.
                Debug.Assert(
                    (rsaPadding == Interop.AndroidCrypto.RsaPadding.NoPadding) ==
                    (rsaPaddingProcessor != null));

                // Caller should have already checked this.
                Debug.Assert(!key.IsInvalid);

                int rsaSize = Interop.AndroidCrypto.RsaSize(key);

                if (data.Length != rsaSize)
                {
                    throw new CryptographicException(SR.Cryptography_RSA_DecryptWrongSize);
                }

                if (destination.Length < rsaSize)
                {
                    bytesWritten = 0;
                    return(false);
                }

                Span <byte> decryptBuf = destination;

                byte[]? paddingBuf = null;

                if (rsaPaddingProcessor != null)
                {
                    paddingBuf = CryptoPool.Rent(rsaSize);
                    decryptBuf = paddingBuf;
                }

                try
                {
                    int returnValue = Interop.AndroidCrypto.RsaPrivateDecrypt(data.Length, data, decryptBuf, key, rsaPadding);
                    CheckReturn(returnValue);

                    if (rsaPaddingProcessor != null)
                    {
                        return(rsaPaddingProcessor.DepadOaep(paddingBuf, destination, out bytesWritten));
                    }
                    else
                    {
                        // If the padding mode is RSA_NO_PADDING then the size of the decrypted block
                        // will be RSA_size. If any padding was used, then some amount (determined by the padding algorithm)
                        // will have been reduced, and only returnValue bytes were part of the decrypted
                        // body.  Either way, we can just use returnValue, but some additional bytes may have been overwritten
                        // in the destination span.
                        bytesWritten = returnValue;
                    }

                    return(true);
                }
                finally
                {
                    if (paddingBuf != null)
                    {
                        // DecryptBuf is paddingBuf if paddingBuf is not null, erase it before returning it.
                        // If paddingBuf IS null then decryptBuf was destination, and shouldn't be cleared.
                        CryptographicOperations.ZeroMemory(decryptBuf);
                        CryptoPool.Return(paddingBuf, clearSize: 0);
                    }
                }
            }
示例#8
0
            public override bool TryDecrypt(
                ReadOnlySpan <byte> data,
                Span <byte> destination,
                RSAEncryptionPadding padding,
                out int bytesWritten)
            {
                ArgumentNullException.ThrowIfNull(padding);

                Interop.AndroidCrypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor? oaepProcessor);
                SafeRsaHandle key = GetKey();

                int keySizeBytes = Interop.AndroidCrypto.RsaSize(key);

                // Android does not take a length value for the destination, so it can write out of bounds.
                // To prevent the OOB write, decrypt into a temporary buffer.
                if (destination.Length < keySizeBytes)
                {
                    Span <byte> tmp = stackalloc byte[0];
                    byte[]? rent = null;

                    // RSA up through 4096 stackalloc
                    if (keySizeBytes <= 512)
                    {
                        tmp = stackalloc byte[keySizeBytes];
                    }
                    else
                    {
                        rent = ArrayPool <byte> .Shared.Rent(keySizeBytes);

                        tmp = rent;
                    }

                    bool ret = TryDecrypt(key, data, tmp, rsaPadding, oaepProcessor, out bytesWritten);

                    if (ret)
                    {
                        tmp = tmp.Slice(0, bytesWritten);

                        if (bytesWritten > destination.Length)
                        {
                            ret          = false;
                            bytesWritten = 0;
                        }
                        else
                        {
                            tmp.CopyTo(destination);
                        }

                        CryptographicOperations.ZeroMemory(tmp);
                    }

                    if (rent != null)
                    {
                        // Already cleared
                        ArrayPool <byte> .Shared.Return(rent);
                    }

                    return(ret);
                }

                return(TryDecrypt(key, data, destination, rsaPadding, oaepProcessor, out bytesWritten));
            }