github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/crypto/des/block.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package des
     6  
     7  import (
     8  	"encoding/binary"
     9  )
    10  
    11  func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) {
    12  	b := binary.BigEndian.Uint64(src)
    13  	b = permuteBlock(b, initialPermutation[:])
    14  	left, right := uint32(b>>32), uint32(b)
    15  
    16  	var subkey uint64
    17  	for i := 0; i < 16; i++ {
    18  		if decrypt {
    19  			subkey = subkeys[15-i]
    20  		} else {
    21  			subkey = subkeys[i]
    22  		}
    23  
    24  		left, right = right, left^feistel(right, subkey)
    25  	}
    26  	// switch left & right and perform final permutation
    27  	preOutput := (uint64(right) << 32) | uint64(left)
    28  	binary.BigEndian.PutUint64(dst, permuteBlock(preOutput, finalPermutation[:]))
    29  }
    30  
    31  // Encrypt one block from src into dst, using the subkeys.
    32  func encryptBlock(subkeys []uint64, dst, src []byte) {
    33  	cryptBlock(subkeys, dst, src, false)
    34  }
    35  
    36  // Decrypt one block from src into dst, using the subkeys.
    37  func decryptBlock(subkeys []uint64, dst, src []byte) {
    38  	cryptBlock(subkeys, dst, src, true)
    39  }
    40  
    41  // DES Feistel function
    42  func feistel(right uint32, key uint64) (result uint32) {
    43  	sBoxLocations := key ^ permuteBlock(uint64(right), expansionFunction[:])
    44  	var sBoxResult uint32
    45  	for i := uint8(0); i < 8; i++ {
    46  		sBoxLocation := uint8(sBoxLocations>>42) & 0x3f
    47  		sBoxLocations <<= 6
    48  		// row determined by 1st and 6th bit
    49  		row := (sBoxLocation & 0x1) | ((sBoxLocation & 0x20) >> 4)
    50  		// column is middle four bits
    51  		column := (sBoxLocation >> 1) & 0xf
    52  		sBoxResult |= uint32(sBoxes[i][row][column]) << (4 * (7 - i))
    53  	}
    54  	return uint32(permuteBlock(uint64(sBoxResult), permutationFunction[:]))
    55  }
    56  
    57  // general purpose function to perform DES block permutations
    58  func permuteBlock(src uint64, permutation []uint8) (block uint64) {
    59  	for position, n := range permutation {
    60  		bit := (src >> n) & 1
    61  		block |= bit << uint((len(permutation)-1)-position)
    62  	}
    63  	return
    64  }
    65  
    66  // creates 16 28-bit blocks rotated according
    67  // to the rotation schedule
    68  func ksRotate(in uint32) (out []uint32) {
    69  	out = make([]uint32, 16)
    70  	last := in
    71  	for i := 0; i < 16; i++ {
    72  		// 28-bit circular left shift
    73  		left := (last << (4 + ksRotations[i])) >> 4
    74  		right := (last << 4) >> (32 - ksRotations[i])
    75  		out[i] = left | right
    76  		last = out[i]
    77  	}
    78  	return
    79  }
    80  
    81  // creates 16 56-bit subkeys from the original key
    82  func (c *desCipher) generateSubkeys(keyBytes []byte) {
    83  	// apply PC1 permutation to key
    84  	key := binary.BigEndian.Uint64(keyBytes)
    85  	permutedKey := permuteBlock(key, permutedChoice1[:])
    86  
    87  	// rotate halves of permuted key according to the rotation schedule
    88  	leftRotations := ksRotate(uint32(permutedKey >> 28))
    89  	rightRotations := ksRotate(uint32(permutedKey<<4) >> 4)
    90  
    91  	// generate subkeys
    92  	for i := 0; i < 16; i++ {
    93  		// combine halves to form 56-bit input to PC2
    94  		pc2Input := uint64(leftRotations[i])<<28 | uint64(rightRotations[i])
    95  		// apply PC2 permutation to 7 byte input
    96  		c.subkeys[i] = permuteBlock(pc2Input, permutedChoice2[:])
    97  	}
    98  }