- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我发现 PHP 中的 openssl_*
方法有一些奇怪的行为。 50% 的时间,它会失败,抛出 Unknown cipher algorithm
,而另外 50% 的时间,它会正确编码我的数据。这是我的代码中的相关片段:
$iv = openssl_random_pseudo_bytes(16);
$hash = openssl_encrypt($raw, "AES-128-CBC", $hashing_secret, OPENSSL_RAW_DATA, $iv);
// send $iv.$hash
使用 openssl_get_cipher_methods
给我:
[0] => AES-128-CBC
...
[81] => aes-128-cbc
所以我知道密码可用。此外,$ openssl ciphers
将 AES-128-CBC 列为系统级别的可用密码(但是,有人告诉我 PHP 的捆绑 openssl 是独立的)
我正在运行 Ubuntu 14.04、php5.5.9-1ubuntu4.14、openssl 1.0.1f 2014 年 1 月 6 日(phpinfo 中列出的版本相同)。如果相关,所有这些代码都通过 nginx/php-fpm 在 Silex 框架下运行。
更新:更多信息...
我做了更多的测试。我写了一个小脚本,只循环 x 次,对一些数据进行编码。
set_error_handler(function() use (&$errorCount) {
$errorCount++;
});
for ($i = 0; $i < $numTests; $i++) {
$hash = openssl_encrypt($data, "AES-128-CBC", $hashing_secret, OPENSSL_RAW_DATA, $iv);
}
如果我在同一台服务器上运行它(通过 php test.php
),它会始终如一地运行 - 即 $errorCount == 0
每次。这让我相信它是:a) silex 或 b) 阻碍功能的 fastcgi 进程 - 我已经添加了这些标签。
虽然现在还不确定从这里去哪里......
第二次更新
我做了更多的测试。我把测试脚本放在 nginx 后面,运行 php-fpm。这里奇怪的是,要么 a) 100% 的时间失败,要么 b) 失败 0 次,而不是两种结果都有一点点。这让我相信是 nginx 或 php-fpm 才是罪魁祸首。
最佳答案
这看起来可能是 OpenSSL 错误锁定错误。您应该确保同一进程空间中的任何时候都只使用一个 OpenSSL 对象。
要验证,请运行测试脚本,使其成为唯一使用 OpenSSL 的脚本。它仍然有 50% 的时间失败吗?还是仅在对脚本进行多个并发访问时才会发生故障?
如果它仍然发生,它几乎必须是 php-fpm 中的错误——它正在实例化函数并且在发生错误之前没有正确清除其数据区域。在那种情况下,我希望它每两次调用失败一次,而不是“平均 50%”,而是每一次偶数调用恰好失败一次。在那种情况下,我会尝试使用不同版本的 OpenSSL。
要锁定 openssl,您可以尝试使用 flock并实例化一个锁文件以供 SSL 函数使用(首先检查锁是否可用,然后运行该函数并解锁)。试试这个,看看它是否有效。如果是这样,您可以研究一种更有效的方法 - 例如,您可以使用 MySQL LOCK() 或 semaphore如果可用的话。
5.5.9 中的异常函数可在 ext/openssl/openssl.c
中找到,抛出的错误是初步检查之一。还没有惊喜:
/* {{{ proto string openssl_encrypt(string data, string method, string password [, long options=0 [, string $iv='']])
Encrypts given data with given method and key, returns raw or base64 encoded string */
PHP_FUNCTION(openssl_encrypt)
{
long options = 0;
char *data, *method, *password, *iv = "";
int data_len, method_len, password_len, iv_len = 0, max_iv_len;
const EVP_CIPHER *cipher_type;
EVP_CIPHER_CTX cipher_ctx;
int i=0, outlen, keylen;
unsigned char *outbuf, *key;
zend_bool free_iv;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|ls", &data, &data_len, &method, &method_len, &password, &password_len, &options, &iv, &iv_len) == FAILURE) {
return;
}
cipher_type = EVP_get_cipherbyname(method);
if (!cipher_type) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
RETURN_FALSE;
}
所以我们可以假设 EVP_get_cipherbyname(method)
返回一个错误。
除了它是一个标准的 SSL 函数。我发现这很简洁(而且很可能已经过时)reply这似乎表明食谱中某处有一些棕榈汁。但这并不能解释为什么函数应该每两次失败一次。
函数是here on github .它初始化 OpenSSL,并通过 ancillary function 获取方法名称。这将返回一个指向非空内存的指针。
我有一个牵强的假设,该函数随机返回类似于 0 或 81 的东西(因为这两个字符串都在您的密码列表输出中,索引为 0 和 81)并且 0 等于 NULL,因此失败。看起来它不能那样工作,它也应该在 CLI 中这样做。 但为了确定,验证是否只有特定密码失败(而例如 AES-256-CBC 有效)。
另一种可能性是 OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS, NULL)
调用失败了。如果这个测试(在 Ubuntu 上;其他平台表现不同)失败,就会发生这种情况:
int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
{
if (pthread_once(once, init) != 0)
return 0;
return 1;
}
这再次表明 libcrypto 内部存在一些共享资源冲突。
作为另一个测试,我建议你不要调用随机字节 IV 初始化并尝试使用固定 IV;那是因为我也偶然发现了 this note ,它指向的资源与我想象的略有不同,但足够接近让我使用react:
It appears that openssl_random_pseudo_bytes(), which calls openssl, causes the underlying libcrypto to invoke a callback that was established previously by PostgreSQL library as part of the lock portability callbacks for multi-threading of openssl.
Some information on the topic can be found here http://wiki.openssl.org/index.php/Manual:Threads(3)
如果 HHVM openssl 扩展没有建立这些相同的回调,它可能会导致调用错误的回调。
如果时间允许,我将要执行的下一个测试是在上述故障点中放置警报(以静态系统日志调用的形式),以准确查明哪个测试失败...只要我可以安装与您在 VM 上相同的设置,并且我可以重现相同的怪异行为。
关于php - openssl 加密/解密工作不一致/失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37146547/
我有一个 C# 应用程序调用 Java 网络服务来验证用户密码。我想让 C# 应用程序加密密码,然后让 Java Web 服务解密密码。我已经完成了 Java 端的代码(解密代码),但我无法找出 C#
我正在使用以下代码在使用 openssl 的 Windows 中使用 C 加密和解密二进制数据。如您所见,在这两个函数中,我都知道纯文本的大小。有什么方法可以在不知道纯文本大小的情况下解密消息? #i
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我有一个非常恼人的问题,Java中使用RSA算法对字符串进行不可靠的加密和解密。它似乎只能在大约 35% 的时间内工作,而且我不明白为什么它有时能工作,有时却不能。这是我写的一些测试代码,试图验证加密
我已经设法编写了用于文件加密/解密的函数。但它非常慢,尤其是随着文件大小的增加。例如几MB长的音频/视频文件 我几乎浏览了所有帖子来改进它,并尝试更改算法。如果有任何更改可以帮助我提高性能,请帮助我。
我正在尝试让我的转置密码发挥作用。 每当我将加密方法得到的密文输入解密方法时,我应该得到原始的明文......但事实并非如此...... 我做错了什么? 感谢您的帮助! public String E
我正在使用密码来加密和解密消息: public String encrypt(String string) throws InvalidKeyException, IllegalBlockSizeEx
我有一个在 MySQL 中存储数据的 spring-mvc 堆栈。其中一些数据需要保护,所以我想我应该加密它。由于我以后可能需要使用这些数据(信用卡、SSN 等),所以我需要对其进行解密。我认为这排除
作为一名SEOER,都想了解百度算法,通过算法原理来找到捷径的优化方案,那么今天我把研究多年的百度算法原理解密给大家,可能不是最好的,但是我可以给大家保证,这些都是非常实际的。希望给SEOER带来一
我试图找到一种技术来加密和解密程序中的文件,而无需将密码硬编码到程序中,也无需向用户询问密码。 如果我也可以从我正在编写的另一个程序中解密文件,那就太好了。 到目前为止,我还没有多少运气找到一种看起来
有没有一种方法可以使用作为字符串参数传递给程序的私钥而不是使用存储在机器上的证书来解密 PowerShell 中的 RSA?欢迎任何帮助,我的代码如下。 Function Decrypt-Asymme
通过问题Is it possible to use the Grails Jasypt plugin outside the GORM layer for simple String encrypti
我需要解密/加密我的域类中的几列,并且正在寻找有关如何做的信息。我已经找到了jasypt加密插件,但不幸的是它似乎与Grails 2.4不兼容。 我可能可以将一些东西拼凑在一起,但是想要确保Im遵循最
我需要有关声音文件加密/解密的帮助。我想在存储这个声音文件时加密一个声音文件,并在播放这个文件时解密它。我阅读了有关 java 中的加密/解密以及 java 中可用于此的大量示例代码。但这些程序不适用
我很感兴趣是否可以使用 Excel Visual Basic 和某些加密服务提供程序进行字符串加密/解密。 我找到了一个演练 Encrypting and Decrypting Strings in
我们正在使用加密/解密和UIIMAGE。如果我们在不保存到iphone画廊的情况下进行加密和解密以及UIIMAge,则可以正常工作,但是,如果我们进行加密,保存到画廊,将(加密的图像)加载到应用程序中
我正在做一个像这样的简单程序: package rsaexample; import java.io.*; import java.math.BigInteger; import java.secur
我发现这段代码返回给定字符串的校验和。 public static String getChecksum(String md5) { int counter = 0; while (c
我在 Java SE 和 Android 项目上使用相同的代码。在 Java 和 Android 中运行的应用程序连接到相同的 MQTT 代理并交换消息。消息使用 AES 进行加密/解密。我对 Jav
我想在 openssl/libcrypto 中使用 RSA 加密/解密一个长文件(我知道 AES 更好,但这只是为了比较)。我将输入文件分成大小为 numBlocks = inputFileLengt
我是一名优秀的程序员,十分优秀!