// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package blowfish // getNextWord returns the next big-endian uint32 value from the byte slice // at the given position in a circular manner, updating the position. func getNextWord(b []byte, pos *int) uint32 { var w uint32 j := *pos for i := 0; i < 4; i++ { w = w<<8 | uint32(b[j]) j++ if j >= len(b) { j = 0 } } *pos = j return w } // ExpandKey performs a key expansion on the given *Cipher. Specifically, it // performs the Blowfish algorithm's key schedule which sets up the *Cipher's // pi and substitution tables for calls to Encrypt. This is used, primarily, // by the bcrypt package to reuse the Blowfish key schedule during its // set up. It's unlikely that you need to use this directly. func ExpandKey(key []byte, c *Cipher) { j := 0 for i := 0; i < 18; i++ { // Using inlined getNextWord for performance. var d uint32 for k := 0; k < 4; k++ { d = d<<8 | uint32(key[j]) j++ if j >= len(key) { j = 0 } } c.p[i] ^= d } var l, r uint32 for i := 0; i < 18; i += 2 { l, r = encryptBlock(l, r, c) c.p[i], c.p[i+1] = l, r } for i := 0; i < 256; i += 2 { l, r = encryptBlock(l, r, c) c.s0[i], c.s0[i+1] = l, r } for i := 0; i < 256; i += 2 { l, r = encryptBlock(l, r, c) c.s1[i], c.s1[i+1] = l, r } for i := 0; i < 256; i += 2 { l, r = encryptBlock(l, r, c) c.s2[i], c.s2[i+1] = l, r } for i := 0; i < 256; i += 2 { l, r = encryptBlock(l, r, c) c.s3[i], c.s3[i+1] = l, r } } // This is similar to ExpandKey, but folds the salt during the key // schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero // salt passed in, reusing ExpandKey turns out to be a place of inefficiency // and specializing it here is useful. func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) { j := 0 for i := 0; i < 18; i++ { c.p[i] ^= getNextWord(key, &j) } j = 0 var l, r uint32 for i := 0; i < 18; i += 2 { l ^= getNextWord(salt, &j) r ^= getNextWord(salt, &j) l, r = encryptBlock(l, r, c) c.p[i], c.p[i+1] = l, r } for i := 0; i < 256; i += 2 { l ^= getNextWord(salt, &j) r ^= getNextWord(salt, &j) l, r = encryptBlock(l, r, c) c.s0[i], c.s0[i+1] = l, r } for i := 0; i < 256; i += 2 { l ^= getNextWord(salt, &j) r ^= getNextWord(salt, &j) l, r = encryptBlock(l, r, c) c.s1[i], c.s1[i+1] = l, r } for i := 0; i < 256; i += 2 { l ^= getNextWord(salt, &j) r ^= getNextWord(salt, &j) l, r = encryptBlock(l, r, c) c.s2[i], c.s2[i+1] = l, r } for i := 0; i < 256; i += 2 { l ^= getNextWord(salt, &j) r ^= getNextWord(salt, &j) l, r = encryptBlock(l, r, c) c.s3[i], c.s3[i+1] = l, r } } func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) { xl, xr := l, r xl ^= c.p[0] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16] xr ^= c.p[17] return xr, xl } func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) { xl, xr := l, r xl ^= c.p[17] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3] xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2] xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1] xr ^= c.p[0] return xr, xl }