热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用AES-128和密钥加密NSString。-EncryptNSStringusingAES-128andakey

Ihaveabasicnotesapp,andIwanttoallowtheusertohaveencryptedorsecurenotes.Ihavean

I have a basic notes app, and I want to allow the user to have encrypted or secure notes. I have an UI whipped up, but right now, I can't seem to get encryption working. Either it returns me a bunch of garbage or nothing at all. This is what I use to en/decrypt:

我有一个基本的notes应用程序,我希望允许用户使用加密或安全的笔记。我有一个UI,但是现在,我似乎无法得到加密。要么它返回给我一堆垃圾,要么什么都没有。这就是我使用的en/decrypt:

- (BOOL) encryptWithAES128Key: (NSString *) key {
    // 'key' should be 16 bytes for AES128, will be null-padded otherwise
    char * keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    // encrypts in-place, since this is a mutable data object
    size_t numBytesEncrypted = 0;
    CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128 , kCCOptionPKCS7Padding, 
                                     keyPtr, kCCKeySizeAES128,
                                     NULL /* initialization vector (optional) */, 
                                     [self mutableBytes], [self length], /* input */
                                     [self mutableBytes], [self length] + kCCBlockSizeAES128, /* output */
                                     &numBytesEncrypted);

    return (result == kCCSuccess);
}

- (NSMutableData *) decryptWithAES128Key: (NSString *) key {
    // 'key' should be 16 bytes for AES128, will be null-padded otherwise
    char * keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    // encrypts in-place, since this is a mutable data object
    size_t bufferSize           = [self length] + kCCBlockSizeAES128;
    void* buffer                = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus result = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 
                                     keyPtr, kCCKeySizeAES128,
                                     NULL /* initialization vector (optional) */, 
                                     [self bytes], [self length], /* input */
                                     buffer, bufferSize, /* output */
                                     &numBytesEncrypted);   


    if(result == kCCSuccess || result == kCCParamError) {
        return [[NSMutableData dataWithBytesNoCopy:buffer length:numBytesEncrypted] retain];
    }

    return nil;
}

Does anyone have any idea why this might be going wrong?

有人知道为什么会这样吗?

Edit 1: I've revised my en/decryption code to be the same. Here is how it looks right now:

编辑1:我已经修改了我的en/解密代码是一样的。下面是它现在的样子:

- (BOOL) encryptWithAES128Key: (NSString *) key {
    CCCryptorStatus ccStatus = kCCSuccess;
    // Symmetric crypto reference.
    CCCryptorRef thisEncipher = NULL;
    // Cipher Text container.
    NSData * cipherOrPlainText = nil;
    // Pointer to output buffer.
    uint8_t * bufferPtr = NULL;
    // Total size of the buffer.
    size_t bufferPtrSize = 0;
    // Remaining bytes to be performed on.
    size_t remainingBytes = 0;
    // Number of bytes moved to buffer.
    size_t movedBytes = 0;
    // Length of plainText buffer.
    size_t plainTextBufferSize = 0;
    // Placeholder for total written.
    size_t totalBytesWritten = 0;
    // A friendly helper pointer.
    uint8_t * ptr;

    // Initialization vector; dummy in this case 0's.
    uint8_t iv[kCCBlockSizeAES128];
    memset((void *) iv, 0x0, (size_t) sizeof(iv));
    plainTextBufferSize = [self length];

    ccStatus = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, (const void *)[key UTF8String], kCCKeySizeAES128, (const void *)iv, &thisEncipher);

    // Calculate byte block alignment for all calls through to and including final.
    bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);

    // Allocate buffer.
    bufferPtr = [self mutableBytes];

    // Zero out buffer.
    //memset((void *)bufferPtr, 0x0, bufferPtrSize);

    // Initialize some necessary book keeping.

    ptr = bufferPtr;

    // Set up initial size.
    remainingBytes = bufferPtrSize;

    // Actually perform the encryption or decryption.
    ccStatus = CCCryptorUpdate(thisEncipher, (const void *) [self bytes], plainTextBufferSize, ptr, remainingBytes, &movedBytes);

    ptr += movedBytes;
    remainingBytes -= movedBytes;
    totalBytesWritten += movedBytes;

    // Finalize everything to the output buffer.
    ccStatus = CCCryptorFinal(thisEncipher, ptr, remainingBytes, &movedBytes);

    cipherOrPlainText = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)totalBytesWritten];
    NSLog(@"data: %@", cipherOrPlainText);

    NSLog(@"buffer: %s", bufferPtr);

    CCCryptorRelease(thisEncipher);
    thisEncipher = NULL;
    if(bufferPtr) free(bufferPtr);
}

- (NSMutableData *) decryptWithAES128Key: (NSString *) key {    
    CCCryptorStatus ccStatus = kCCSuccess;
    // Symmetric crypto reference.
    CCCryptorRef thisEncipher = NULL;
    // Cipher Text container.
    NSData * cipherOrPlainText = nil;
    // Pointer to output buffer.
    uint8_t * bufferPtr = NULL;
    // Total size of the buffer.
    size_t bufferPtrSize = 0;
    // Remaining bytes to be performed on.
    size_t remainingBytes = 0;
    // Number of bytes moved to buffer.
    size_t movedBytes = 0;
    // Length of plainText buffer.
    size_t plainTextBufferSize = 0;
    // Placeholder for total written.
    size_t totalBytesWritten = 0;
    // A friendly helper pointer.
    uint8_t * ptr;

    // Initialization vector; dummy in this case 0's.
    uint8_t iv[kCCBlockSizeAES128];
    memset((void *) iv, 0x0, (size_t) sizeof(iv));
    plainTextBufferSize = [self length];

    ccStatus = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, (const void *)[key UTF8String], kCCKeySizeAES128, (const void *)iv, &thisEncipher);

    // Calculate byte block alignment for all calls through to and including final.
    bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);

    // Allocate buffer.
    bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t) );

    // Zero out buffer.
    memset((void *)bufferPtr, 0x0, bufferPtrSize);

    // Initialize some necessary book keeping.

    ptr = bufferPtr;

    // Set up initial size.
    remainingBytes = bufferPtrSize;

    // Actually perform the encryption or decryption.
    ccStatus = CCCryptorUpdate(thisEncipher, (const void *) [self bytes], plainTextBufferSize, ptr, remainingBytes, &movedBytes);

    ptr += movedBytes;
    remainingBytes -= movedBytes;
    totalBytesWritten += movedBytes;

    // Finalize everything to the output buffer.
    ccStatus = CCCryptorFinal(thisEncipher, ptr, remainingBytes, &movedBytes);

    cipherOrPlainText = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)totalBytesWritten];
    NSLog(@"data: %@", cipherOrPlainText);

    NSLog(@"buffer: %s", bufferPtr);

    CCCryptorRelease(thisEncipher);
    thisEncipher = NULL;
    if(bufferPtr) free(bufferPtr);

    return [NSMutableData dataWithData:cipherOrPlainText];
}

This code somewhat works. If I encrypt this string with the passphrase '1234567890123456':

这段代码有些作品。如果我用passphrase '1234567890123456'来加密这个字符串:




    dict
    
        device
        Tristan's Magical Macbook of Death
        text
        e1xydGYxXGFuc2lcYW5zaWNwZzEyNTJcY29jb2FydGYxMDM4XGNvY29hc3VicnRm
MzYwCntcZm9udHRibFxmMFxmc3dpc3NcZmNoYXJzZXQwIEhlbHZldGljYTt9Cntc
Y29sb3J0Ymw7XHJlZDI1NVxncmVlbjI1NVxibHVlMjU1O30KXHBhcmRcdHg1NjBc
dHgxMTIwXHR4MTY4MFx0eDIyNDBcdHgyODAwXHR4MzM2MFx0eDM5MjBcdHg0NDgw
XHR4NTA0MFx0eDU2MDBcdHg2MTYwXHR4NjcyMFxxbFxxbmF0dXJhbFxwYXJkaXJu
YXR1cmFsCgpcZjBcZnMyNCBcY2YwIFx1bCBcdWxjMCBCTEFILn0=

        title
        Welcome to Notepaddy!
        uuid
        5yvghz9n4ukgefnbx0qa2xne3nxeebcmcvpci9j5lwpncul1asftdayjv8a
    
    text
    e1xydGYxXGFuc2lcYW5zaWNwZzEyNTJcY29jb2FydGYxMDM4XGNvY29hc3VicnRm
MzYwCntcZm9udHRibFxmMFxmc3dpc3NcZmNoYXJzZXQwIEhlbHZldGljYTt9Cntc
Y29sb3J0Ymw7XHJlZDI1NVxncmVlbjI1NVxibHVlMjU1O30KXHBhcmRcdHg1NjBc
dHgxMTIwXHR4MTY4MFx0eDIyNDBcdHgyODAwXHR4MzM2MFx0eDM5MjBcdHg0NDgw
XHR4NTA0MFx0eDU2MDBcdHg2MTYwXHR4NjcyMFxxbFxxbmF0dXJhbFxwYXJkaXJu
YXR1cmFsCgpcZjBcZnMyNCBcY2YwIFx1bCBcdWxjMCBCTEFILn0=

    title
    Welcome to Notepaddy!
    uuid
    5yvghz9n4ukgefnbx0qa2xne3nxeebcmcvpci9j5lwpncul1asftdayjv8a


I get the same text back, but the entire is missing and the is cut off. Decrypting and printing the result string out gives me complete garbage when encrypted with the passphrase '0987654321123456' or any other passphrase, or the same as above when copied into the password field.

我得到了相同的文本,但是整个缺失了,被切断了。解密和打印结果字符串,在使用passphrase '0987654321123456'或任何其他密码,或在复制到密码字段时使用的任何其他密码,都给了我完整的垃圾。

4 个解决方案

#1


5  

Both versions have the same problem: You tell CommonCrypto to write past the end of your buffer, and then you ignore the result.

两个版本都有相同的问题:您告诉CommonCrypto在缓冲区的末尾写入,然后忽略结果。

The first version:

第一个版本:

[self mutableBytes], [self length] + kCCBlockSizeAES128, /* output */

The second version:

第二个版本:

// Calculate byte block alignment for all calls through to and including final.
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);

// Allocate buffer.
bufferPtr = [self mutableBytes];

That's not right. You're not allocating anything. You're telling it to write bufferPtrSize bytes to a buffer of size [self length]!

这是不正确的。你没有分配任何东西。您是在告诉它将bufferPtrSize字节写入一个大小缓冲区(self length) !

You want to do something more like this (if you really want to encrypt in-place):

你想做一些更像这样的事情(如果你真的想要加密):

// Calculate byte block alignment for all calls through to and including final.
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);
// Increase my size if necessary:
if (bufferPtrSize > self.length) {
  self.length = bufferPtrSize;
}

I'm also not sure why encrypting is in-place while decrypting is not; the latter is, if anything, easier to do.

我也不知道为什么加密是正确的,而解密却不是;后者,如果有的话,更容易做到。

Your second version has an additional problems:

你的第二个版本有另外一个问题:

  • You free something you didn't allocate: if(bufferPtr) free(bufferPtr);
  • 您免费提供一些您没有分配的东西:如果(bufferPtr)免费(bufferPtr);
  • You potentially read past the end of the string: (const void *)[key UTF8String], kCCKeySizeAES128
  • 您可能阅读过字符串的末尾:(const void *)[key UTF8String], kCCKeySizeAES128。

Additional crypto problems:

额外的加密问题:

  • Keys are supposed to be fixed-size and have a decent amount of entropy. Naively converting a string to bytes does not a good key make (for one, keys longer than 16 bytes are effectively truncated). The least you could do is hash it. You might also want to iterate the hash, or just use PBKDF2 (admittedly I haven't found the spec/test vectors for PBKDF2...)
  • 密钥应该是固定大小的,并且有相当数量的熵。天真地将字符串转换成字节并不是一个好键(对于一个,键长超过16个字节实际上被截断)。你至少可以把它哈希。您可能还需要迭代哈希,或者只是使用PBKDF2(必须承认,我还没有找到PBKDF2的规范/测试向量…)
  • You almost certainly want to use a random IV too (see SecRandomCopyBytes).
  • 您几乎肯定也想使用一个随机的IV(参见SecRandomCopyBytes)。

Addendum:

附录:

The reason why you're seeing a truncated result is because you're returning a truncated answer (with PKCS7 padding, the encrypted result is always bigger than the original data). Chances (about 255/256) are that the last ciphertext block was incorrectly padded (because you gave CCryptor truncated data), so ccStatus says an error happened but you ignored this and returned the result anyway. This is incredibly bad practice. (Additionally, you really want to use a MAC with CBC to avoid the padding oracle security hole.)

您看到一个截断结果的原因是您返回一个截断的答案(使用PKCS7填充,加密的结果总是比原始数据更大)。机会(大约255/256)是最后一个密文块被错误地填充了(因为您给了CCryptor截断的数据),所以ccStatus说一个错误发生了,但是您忽略了这个,并且返回了结果。这是非常糟糕的做法。(另外,您确实希望使用CBC的MAC来避免填充oracle安全漏洞。)

EDIT:

编辑:

Some code that seems to work looks something like this (complete with test cases):

一些看起来工作的代码看起来像这样(用测试用例完成):

Notes:

注:

  • Not actually tested on iOS (though the non-iOS code should work on iOS; it's just that SecRandomCopyBytes is a slightly nicer interface but not available on OS X).
  • 还没有在iOS上进行测试(尽管非iOS的代码应该在iOS上运行;只是SecRandomCopyBytes是一个稍微好一些的接口,但在OS X上是不可用的。
  • The read() loop might be right, but is not thoroughly tested.
  • read()循环可能是正确的,但是没有经过彻底的测试。
  • The ciphertext is prefixed with the IV. This is the "textbook" method, but makes ciphertexts bigger.
  • 密文以四为前缀,这是“教科书”的方法,但使密文更大。
  • There is no authentication, so this code can act as a padding oracle.
  • 没有身份验证,因此这段代码可以充当填充oracle。
  • There is no support for AES-192 or AES-256. It would not be difficult to add (you'd just need to switch on the key length and pick the algorithm appropriately).
  • 对AES-192或AES-256没有支持。添加(您只需要打开密钥长度并适当地选择算法)就不难了。
  • The key is specified as a NSData, so you'll need to do something like [string dataUsingEncoding:NSUTF8StringEncoding]. For bonus points, run it through CC_SHA256 and take the first 16 output bytes.
  • 键被指定为NSData,所以您需要做一些类似于[string dataUsingEncoding:NSUTF8StringEncoding]的操作。对于积分,可以通过CC_SHA256运行它,并获取前16个输出字节。
  • There's no in-place operation. I didn't think it was worth it.
  • 没有就地操作。我不认为这是值得的。

.

#include 
#include 

#if TARGET_OS_IPHONE
#include 
#else
#include 
#include 
#endif

@interface NSData(AES)
- (NSData*) encryptedDataUsingAESKey: (NSData *) key;
- (NSData*) decryptedDataUsingAESKey: (NSData *) key;
@end
@implementation NSData(AES)

- (NSData*) encryptedDataUsingAESKey: (NSData *) key {
        uint8_t iv[kCCBlockSizeAES128];
#if TARGET_OS_IPHONE
        if (0 != SecRandomCopyBytes(kSecRandomDefault, sizeof(iv), iv))
        {
                return nil;
        }
#else
        {
                int fd = open("/dev/urandom", O_RDONLY);
                if (fd <0) { return nil; }
                ssize_t bytesRead;
                for (uint8_t * p = iv; (bytesRead = read(fd,p,iv+sizeof(iv)-p)); p += (size_t)bytesRead) {
                        // 0 means EOF.
                        if (bytesRead == 0) { close(fd); return nil; }
                        // -1, EINTR means we got a system call before any data could be read.
                        // Pretend we read 0 bytes (since we already handled EOF).
                        if (bytesRead <0 && errno == EINTR) { bytesRead = 0; }
                        // Other errors are real errors.
                        if (bytesRead <0) { close(fd); return nil; }
                }
                close(fd);
        }
#endif
        size_t retSize = 0;
        CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 
                                     [key bytes], [key length],
                                     iv,
                                     [self bytes], [self length],
                                     NULL, 0,
                                     &retSize);
        if (result != kCCBufferTooSmall) { return nil; }

        // Prefix the data with the IV (the textbook method).
        // This requires adding sizeof(iv) in a few places later; oh well.
        void * retPtr = malloc(retSize+sizeof(iv));
        if (!retPtr) { return nil; }

        // Copy the IV.
        memcpy(retPtr, iv, sizeof(iv));

        result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 
                                     [key bytes], [key length],
                                     iv,
                                     [self bytes], [self length],
                                     retPtr+sizeof(iv),retSize,
                                     &retSize);
        if (result != kCCSuccess) { free(retPtr); return nil; }

        NSData * ret = [NSData dataWithBytesNoCopy:retPtr length:retSize+sizeof(iv)];
        // Does +[NSData dataWithBytesNoCopy:length:] free if allocation of the NSData fails?
        // Assume it does.
        if (!ret) { free(retPtr); return nil; }
        return ret;
}

- (NSData*) decryptedDataUsingAESKey: (NSData *) key {
        const uint8_t * p = [self bytes];
        size_t length = [self length];
        if (length 

#2


1  

Regarding your *de*cryption code

kCCParamError is, as its name says, an error. Why are you treating it as success? If you get that error, it means you did something wrong; look at the parameters you passed and figure out what.

正如其名,kCCParamError是一个错误。你为什么把它当作成功?如果你犯了这个错误,就意味着你做错了什么;看看你传递的参数并找出其中的原因。

This is probably why you're getting “garbage”: CCCrypt (decrypting) never actually gave you anything, because it could not work with whatever values you gave it. What you're getting is whatever was lying around in the output buffer when you allocated it.

这可能就是你得到“垃圾”的原因:CCCrypt(解密)从来没有给过你任何东西,因为它不能与你提供的任何值一起工作。你得到的是当你分配它的时候在输出缓冲区里的任何东西。

If you switch to calloc or to creating the NSMutableData object before calling CCCrypt and using its mutableBytes as the buffer, I think you'll find that the buffer then always contains all zeroes. Same reason: CCCrypt is not filling it out, because it's failing, because you passed one or more wrong values (parameter error).

如果切换到calloc或在调用CCCrypt之前创建NSMutableData对象,并使用其mutableBytes作为缓冲区,我想你会发现缓冲区总是包含所有的零。同样的原因:CCCrypt没有填充它,因为它失败了,因为您传递了一个或多个错误的值(参数错误)。

You need to fix the parameter error before you can expect this to work.

您需要修正参数错误,然后才能期望它工作。

You might try breaking the CCCrypt call into calls to CCCryptorCreate, CCCryptorUpdate, CCCryptorFinal, and CCCryptorRelease, at least temporarily, to see where it's going wrong.

您可能会尝试将CCCrypt调用分解为对CCCryptorCreate、CCCryptorUpdate、CCCryptorFinal和CCCryptorRelease的调用,至少是暂时的,看看哪里出错了。

Encryption: The same problem, or no problem at all

Is your encryption method returning YES or NO? I'm guessing it returns NO, because the code appears to be mostly the same between the encryption and decryption methods, so whatever you have wrong in your decryption code is probably wrong in your encryption code as well. See what CCCrypt is returning and, if it's failing, get it working.

您的加密方法是否返回YES或NO?我猜它会返回NO,因为代码在加密和解密方法之间几乎是相同的,所以在你的解密代码中任何错误都可能在你的加密代码中是错误的。看看CCCrypt返回了什么,如果失败了,让它工作。

If it is returning YES (CCCrypt is succeeding), then I wonder what you mean by “returns me a bunch of garbage”. Are you referring to the contents of the data object you sent the encryptWithAES128Key: message to?

如果它返回YES (CCCrypt正在成功),那么我想知道您的意思是什么“返回一堆垃圾”。您是指您发送的encryptWithAES128Key:消息到的数据对象的内容吗?

If that's the case, then that is the expected result. Your code encrypts the contents of the data object in place, overwriting the cleartext with the ciphertext. What you're seeing isn't pure “garbage”—it's the ciphertext! Decrypting it (successfully) will reveal the cleartext again.

如果是这样的话,那就是预期的结果。您的代码对数据对象的内容进行加密,以密文覆盖明文。你看到的不是纯粹的“垃圾”,而是密文!解密(成功)将再次显示明文。

By the way, you have the “encrypts in-place, since this is a mutable data object” comment on the creation of an output buffer in order to not work in-place in the decryption code. It should be in the encryption method, where you are working in-place. I suggest making either both work in-place or neither work in-place; consistency is a virtue.

顺便说一下,您有“就地加密,因为这是一个可变的数据对象”对输出缓冲区的创建进行注释,以便在解密代码中不工作。它应该在加密方法中,在那里你正在工作。我建议要么在工作中要么在原地工作,要么不工作;一致性是一种美德。

#3


0  

If you have following padding changes in your code remove it and always keep kCCOptionPKCS7Padding on, this should solve your issue.

如果您在代码中有以下修改,请删除它,并始终保持kCCOptionPKCS7Padding,这将解决您的问题。

if (encryptOrDecrypt == kCCEncrypt) {
    if (*pkcs7 != kCCOptionECBMode) {
        if ((plainTextBufferSize % kChosenCipherBlockSize) == 0) {
            *pkcs7 = 0x0000;
        } else {
            *pkcs7 = kCCOptionPKCS7Padding;
        }
    }
}

#4


0  

You should use RNCryptor, it's high level encryption opensource api around CommonCrypto, and high level encryption API's are the best practice for cryptography these days, because it's easy for experts to make mistakes in the implementations using crypto primatives, and there are alot of side channel attacks out there that take advantage of those mistakes.

您应该使用RNCryptor,高度加密CommonCrypto开源api,和高级加密api是密码学的最佳实践这些天,因为专家犯错很容易实现使用加密原语,还有很多的侧信道攻击利用这些错误。

For example, you code says /* initialization vector (optional) * / 100% not true, thus you've totally crippled AES-CBC, and that's just the most obvious issue.

例如,您的代码说/*初始化向量(可选)* / 100%不正确,因此您完全瘫痪了AES-CBC,这是最明显的问题。

In your case RNCryptor is ideal, I'd strongly suggest you don't roll your own implementation.

在您的情况下,RNCryptor是理想的,我强烈建议您不要执行自己的实现。


推荐阅读
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
author-avatar
爱情失挖_904
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有