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
5package des
6
7import (
8	"crypto/cipher"
9	"encoding/binary"
10	"strconv"
11)
12
13// The DES block size in bytes.
14const BlockSize = 8
15
16type KeySizeError int
17
18func (k KeySizeError) Error() string {
19	return "crypto/des: invalid key size " + strconv.Itoa(int(k))
20}
21
22// desCipher is an instance of DES encryption.
23type desCipher struct {
24	subkeys [16]uint64
25}
26
27// NewCipher creates and returns a new cipher.Block.
28func NewCipher(key []byte) (cipher.Block, error) {
29	if len(key) != 8 {
30		return nil, KeySizeError(len(key))
31	}
32
33	c := new(desCipher)
34	c.generateSubkeys(key)
35	return c, nil
36}
37
38func (c *desCipher) BlockSize() int { return BlockSize }
39
40func (c *desCipher) Encrypt(dst, src []byte) { encryptBlock(c.subkeys[:], dst, src) }
41
42func (c *desCipher) Decrypt(dst, src []byte) { decryptBlock(c.subkeys[:], dst, src) }
43
44// A tripleDESCipher is an instance of TripleDES encryption.
45type tripleDESCipher struct {
46	cipher1, cipher2, cipher3 desCipher
47}
48
49// NewTripleDESCipher creates and returns a new cipher.Block.
50func NewTripleDESCipher(key []byte) (cipher.Block, error) {
51	if len(key) != 24 {
52		return nil, KeySizeError(len(key))
53	}
54
55	c := new(tripleDESCipher)
56	c.cipher1.generateSubkeys(key[:8])
57	c.cipher2.generateSubkeys(key[8:16])
58	c.cipher3.generateSubkeys(key[16:])
59	return c, nil
60}
61
62func (c *tripleDESCipher) BlockSize() int { return BlockSize }
63
64func (c *tripleDESCipher) Encrypt(dst, src []byte) {
65	b := binary.BigEndian.Uint64(src)
66	b = permuteInitialBlock(b)
67	left, right := uint32(b>>32), uint32(b)
68
69	left = (left << 1) | (left >> 31)
70	right = (right << 1) | (right >> 31)
71
72	for i := 0; i < 8; i++ {
73		left, right = feistel(left, right, c.cipher1.subkeys[2*i], c.cipher1.subkeys[2*i+1])
74	}
75	for i := 0; i < 8; i++ {
76		right, left = feistel(right, left, c.cipher2.subkeys[15-2*i], c.cipher2.subkeys[15-(2*i+1)])
77	}
78	for i := 0; i < 8; i++ {
79		left, right = feistel(left, right, c.cipher3.subkeys[2*i], c.cipher3.subkeys[2*i+1])
80	}
81
82	left = (left << 31) | (left >> 1)
83	right = (right << 31) | (right >> 1)
84
85	preOutput := (uint64(right) << 32) | uint64(left)
86	binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput))
87}
88
89func (c *tripleDESCipher) Decrypt(dst, src []byte) {
90	b := binary.BigEndian.Uint64(src)
91	b = permuteInitialBlock(b)
92	left, right := uint32(b>>32), uint32(b)
93
94	left = (left << 1) | (left >> 31)
95	right = (right << 1) | (right >> 31)
96
97	for i := 0; i < 8; i++ {
98		left, right = feistel(left, right, c.cipher3.subkeys[15-2*i], c.cipher3.subkeys[15-(2*i+1)])
99	}
100	for i := 0; i < 8; i++ {
101		right, left = feistel(right, left, c.cipher2.subkeys[2*i], c.cipher2.subkeys[2*i+1])
102	}
103	for i := 0; i < 8; i++ {
104		left, right = feistel(left, right, c.cipher1.subkeys[15-2*i], c.cipher1.subkeys[15-(2*i+1)])
105	}
106
107	left = (left << 31) | (left >> 1)
108	right = (right << 31) | (right >> 1)
109
110	preOutput := (uint64(right) << 32) | uint64(left)
111	binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput))
112}
113