Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Retiring crypt (tedunangst.com)
69 points by zdw on Nov 20, 2014 | hide | past | favorite | 16 comments


Ducking

The printf("%s %s", foo(), foo()) problem is unusual for crypt() --- but it isn't for other functions that return points to global static memory, inet_ntoa() in particular (you often want to print both source and destination addresses). To get around this, I used to have a preloaded inet_ntoa that alternated between two global static buffers. :)


Preloading a version that alternates between two buffers is clearly Wrong, but I'm not sure what the right solution is - do you/does anyone have a pattern that they find works well for them?

Our codebase has quite a few functions like inet_ntoa():

    /* returns ptr. to internal static storage */
    const char *type_to_str(const Type *type);
You could pass an explicit argument, but that's pretty ugly:

    /* Explicit buffer argument */
    char msg_buf1[256], msg_buf2[256], msg_buf3[256], ..., msg_buf16[256];
    char *type_to_str(char *buf_to_use, size_t buf_size, const Type *type)
Alternatively, you could give C99 a workout and abuse compound literals as anonymous storage:

    #include <stdio.h>
    
    struct foo {
        int      bar;   
    };  
    
    #define FOO_TO_STR_SIZE 256
    
    #define foo_to_str(foo) \
        foo_to_str_((char [FOO_TO_STR_SIZE]){ 0 }, FOO_TO_STR_SIZE, (foo))

    /* Implementation detail */  
    __attribute__((nonnull))
    static char *foo_to_str_(char *buf_to_use, size_t size,
        const struct foo *foo)
    {   
        (void)snprintf(buf_to_use, size, "%d", foo->bar);
    
        return buf_to_use;
    }
    
    int main(void)
    {
        const struct foo foo = {
            .bar = 42
        },               foo2 = {
            .bar = 43
        };
        printf("%s %s\n", foo_to_str(&foo),
            foo_to_str(&foo2));
    
        return 0;
    }   
(Warning: this is probably too clever. Note that you need the explicit size argument if you offer a library, or you risk your callers using a different FOO_TO_STR_SIZE than you do. There is probably a very minor performance penalty to this solution as the caller must, in general, completely initialize the string. Note the gcc warnings about compound literals in C++ - see https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html for a discussion.)


It's morally wrong, but since you usually only ever want to print two IP addresses, it feels so right. In any case: it can't break otherwise-correct code.


I don't see what's ugly about passing a buffer and size. That's exactly what inet_ntoa()'s modern replacement inet_ntop() does.


returning a const char is absolutely fine - I assume your type name is allocated when the type is and never changes, and you have locking if necessary.


There aren't that many left though, they are a terrible idea.

The NetBSD man page for inet_ntoa lists "The string returned by inet_ntoa() resides in a static memory area" in the BUGS section, Linux is not so forward about it.


The Linux man page says:

  The string is returned in a statically allocated buffer, which subsequent calls will overwrite.


The PHC is defining a standard API which works with all the proposed algorithms as part of the contest. There's a lot that a proper password hashing API can provide and be secure by default. The PHC mailing list has pretty extensive discussion on this topic.

[1] - http://dir.gmane.org/gmane.comp.security.phc


PHP has a pretty nice password_hash API, would be nice if other languages copied it: http://php.net/password_hash

  string password_hash ( string $password , integer $algo [, array $options ] )
  boolean password_verify ( string $password , string $hash )
  boolean password_needs_rehash ( string $hash , integer $algo [, array $options ] )


Where I work we still have many solaris machines and our logins are managed via NIS. Is there a hashing function that is supported for logins on solaris, linux and BSD that we can use other than the DES based one?


Solaris 9+, recentish Linux, and recentish BSD should all support algorithm $1$ (MD5) at an absolute minimum. Depending on OS versions, you might also be able to choose from $2a$ (Blowfish), $5$ (SHA-256), and $6$ (SHA-512). On Solaris, the list of supported algorithms is in /etc/security/crypt.conf. "man 3 crypt" might tell you what's supported on your Linux and BSD machines.

For NIS, you'd need to ensure that every machine that touches passwords via NIS is configured to use the same algorithm when users change passwords. On Solaris, just configure CRYPT_* in /etc/security/policy.conf the same on every machine. (See the policy.conf man page — in short, you want to change the default algorithm to 1 [or whatever] and set __unix__ to be deprecated.) On Linux and *BSD, how you do it depends on the distro/version.

Fun fact about changing passwords in NIS: When a yppasswd client contacts rpc.yppasswdd to change a user's password, the user's new password is sent crypt()ed, but the user's old password is sent in the clear.


Out of curiosity, have you considered migrating to LDAP?



The author is an OpenBSD developer talking about crypt(3) which supports bcrypt hashes: http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/...

OpenBSD implemented bcrypt more than 17 years ago http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/crypt/...


Could you elaborate on that? The article explicitly mentions bcrypt, so what's the point you are trying to make?


I would guess he was trying to mock the meme that everyone says whenever the question of storing passwords comes up here.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: