mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-12-04 17:42:46 +00:00
110 lines
2.5 KiB
Go
110 lines
2.5 KiB
Go
|
/*-
|
||
|
* Copyright 2014 Square Inc.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package josecipher
|
||
|
|
||
|
import (
|
||
|
"crypto/cipher"
|
||
|
"crypto/subtle"
|
||
|
"encoding/binary"
|
||
|
"errors"
|
||
|
)
|
||
|
|
||
|
var defaultIV = []byte{0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}
|
||
|
|
||
|
// KeyWrap implements NIST key wrapping; it wraps a content encryption key (cek) with the given block cipher.
|
||
|
func KeyWrap(block cipher.Block, cek []byte) ([]byte, error) {
|
||
|
if len(cek)%8 != 0 {
|
||
|
return nil, errors.New("square/go-jose: key wrap input must be 8 byte blocks")
|
||
|
}
|
||
|
|
||
|
n := len(cek) / 8
|
||
|
r := make([][]byte, n)
|
||
|
|
||
|
for i := range r {
|
||
|
r[i] = make([]byte, 8)
|
||
|
copy(r[i], cek[i*8:])
|
||
|
}
|
||
|
|
||
|
buffer := make([]byte, 16)
|
||
|
tBytes := make([]byte, 8)
|
||
|
copy(buffer, defaultIV)
|
||
|
|
||
|
for t := 0; t < 6*n; t++ {
|
||
|
copy(buffer[8:], r[t%n])
|
||
|
|
||
|
block.Encrypt(buffer, buffer)
|
||
|
|
||
|
binary.BigEndian.PutUint64(tBytes, uint64(t+1))
|
||
|
|
||
|
for i := 0; i < 8; i++ {
|
||
|
buffer[i] = buffer[i] ^ tBytes[i]
|
||
|
}
|
||
|
copy(r[t%n], buffer[8:])
|
||
|
}
|
||
|
|
||
|
out := make([]byte, (n+1)*8)
|
||
|
copy(out, buffer[:8])
|
||
|
for i := range r {
|
||
|
copy(out[(i+1)*8:], r[i])
|
||
|
}
|
||
|
|
||
|
return out, nil
|
||
|
}
|
||
|
|
||
|
// KeyUnwrap implements NIST key unwrapping; it unwraps a content encryption key (cek) with the given block cipher.
|
||
|
func KeyUnwrap(block cipher.Block, ciphertext []byte) ([]byte, error) {
|
||
|
if len(ciphertext)%8 != 0 {
|
||
|
return nil, errors.New("square/go-jose: key wrap input must be 8 byte blocks")
|
||
|
}
|
||
|
|
||
|
n := (len(ciphertext) / 8) - 1
|
||
|
r := make([][]byte, n)
|
||
|
|
||
|
for i := range r {
|
||
|
r[i] = make([]byte, 8)
|
||
|
copy(r[i], ciphertext[(i+1)*8:])
|
||
|
}
|
||
|
|
||
|
buffer := make([]byte, 16)
|
||
|
tBytes := make([]byte, 8)
|
||
|
copy(buffer[:8], ciphertext[:8])
|
||
|
|
||
|
for t := 6*n - 1; t >= 0; t-- {
|
||
|
binary.BigEndian.PutUint64(tBytes, uint64(t+1))
|
||
|
|
||
|
for i := 0; i < 8; i++ {
|
||
|
buffer[i] = buffer[i] ^ tBytes[i]
|
||
|
}
|
||
|
copy(buffer[8:], r[t%n])
|
||
|
|
||
|
block.Decrypt(buffer, buffer)
|
||
|
|
||
|
copy(r[t%n], buffer[8:])
|
||
|
}
|
||
|
|
||
|
if subtle.ConstantTimeCompare(buffer[:8], defaultIV) == 0 {
|
||
|
return nil, errors.New("square/go-jose: failed to unwrap key")
|
||
|
}
|
||
|
|
||
|
out := make([]byte, n*8)
|
||
|
for i := range r {
|
||
|
copy(out[i*8:], r[i])
|
||
|
}
|
||
|
|
||
|
return out, nil
|
||
|
}
|