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	"crypto/internal/alias"
10	"internal/byteorder"
11	"strconv"
12)
13
14// The DES block size in bytes.
15const BlockSize = 8
16
17type KeySizeError int
18
19func (k KeySizeError) Error() string {
20	return "crypto/des: invalid key size " + strconv.Itoa(int(k))
21}
22
23// desCipher is an instance of DES encryption.
24type desCipher struct {
25	subkeys [16]uint64
26}
27
28// NewCipher creates and returns a new [cipher.Block].
29func NewCipher(key []byte) (cipher.Block, error) {
30	if len(key) != 8 {
31		return nil, KeySizeError(len(key))
32	}
33
34	c := new(desCipher)
35	c.generateSubkeys(key)
36	return c, nil
37}
38
39func (c *desCipher) BlockSize() int { return BlockSize }
40
41func (c *desCipher) Encrypt(dst, src []byte) {
42	if len(src) < BlockSize {
43		panic("crypto/des: input not full block")
44	}
45	if len(dst) < BlockSize {
46		panic("crypto/des: output not full block")
47	}
48	if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
49		panic("crypto/des: invalid buffer overlap")
50	}
51	cryptBlock(c.subkeys[:], dst, src, false)
52}
53
54func (c *desCipher) Decrypt(dst, src []byte) {
55	if len(src) < BlockSize {
56		panic("crypto/des: input not full block")
57	}
58	if len(dst) < BlockSize {
59		panic("crypto/des: output not full block")
60	}
61	if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
62		panic("crypto/des: invalid buffer overlap")
63	}
64	cryptBlock(c.subkeys[:], dst, src, true)
65}
66
67// A tripleDESCipher is an instance of TripleDES encryption.
68type tripleDESCipher struct {
69	cipher1, cipher2, cipher3 desCipher
70}
71
72// NewTripleDESCipher creates and returns a new [cipher.Block].
73func NewTripleDESCipher(key []byte) (cipher.Block, error) {
74	if len(key) != 24 {
75		return nil, KeySizeError(len(key))
76	}
77
78	c := new(tripleDESCipher)
79	c.cipher1.generateSubkeys(key[:8])
80	c.cipher2.generateSubkeys(key[8:16])
81	c.cipher3.generateSubkeys(key[16:])
82	return c, nil
83}
84
85func (c *tripleDESCipher) BlockSize() int { return BlockSize }
86
87func (c *tripleDESCipher) Encrypt(dst, src []byte) {
88	if len(src) < BlockSize {
89		panic("crypto/des: input not full block")
90	}
91	if len(dst) < BlockSize {
92		panic("crypto/des: output not full block")
93	}
94	if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
95		panic("crypto/des: invalid buffer overlap")
96	}
97
98	b := byteorder.BeUint64(src)
99	b = permuteInitialBlock(b)
100	left, right := uint32(b>>32), uint32(b)
101
102	left = (left << 1) | (left >> 31)
103	right = (right << 1) | (right >> 31)
104
105	for i := 0; i < 8; i++ {
106		left, right = feistel(left, right, c.cipher1.subkeys[2*i], c.cipher1.subkeys[2*i+1])
107	}
108	for i := 0; i < 8; i++ {
109		right, left = feistel(right, left, c.cipher2.subkeys[15-2*i], c.cipher2.subkeys[15-(2*i+1)])
110	}
111	for i := 0; i < 8; i++ {
112		left, right = feistel(left, right, c.cipher3.subkeys[2*i], c.cipher3.subkeys[2*i+1])
113	}
114
115	left = (left << 31) | (left >> 1)
116	right = (right << 31) | (right >> 1)
117
118	preOutput := (uint64(right) << 32) | uint64(left)
119	byteorder.BePutUint64(dst, permuteFinalBlock(preOutput))
120}
121
122func (c *tripleDESCipher) Decrypt(dst, src []byte) {
123	if len(src) < BlockSize {
124		panic("crypto/des: input not full block")
125	}
126	if len(dst) < BlockSize {
127		panic("crypto/des: output not full block")
128	}
129	if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
130		panic("crypto/des: invalid buffer overlap")
131	}
132
133	b := byteorder.BeUint64(src)
134	b = permuteInitialBlock(b)
135	left, right := uint32(b>>32), uint32(b)
136
137	left = (left << 1) | (left >> 31)
138	right = (right << 1) | (right >> 31)
139
140	for i := 0; i < 8; i++ {
141		left, right = feistel(left, right, c.cipher3.subkeys[15-2*i], c.cipher3.subkeys[15-(2*i+1)])
142	}
143	for i := 0; i < 8; i++ {
144		right, left = feistel(right, left, c.cipher2.subkeys[2*i], c.cipher2.subkeys[2*i+1])
145	}
146	for i := 0; i < 8; i++ {
147		left, right = feistel(left, right, c.cipher1.subkeys[15-2*i], c.cipher1.subkeys[15-(2*i+1)])
148	}
149
150	left = (left << 31) | (left >> 1)
151	right = (right << 31) | (right >> 1)
152
153	preOutput := (uint64(right) << 32) | uint64(left)
154	byteorder.BePutUint64(dst, permuteFinalBlock(preOutput))
155}
156