mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-11 11:06:29 +00:00
119 lines
2.9 KiB
Go
119 lines
2.9 KiB
Go
|
package crypto
|
||
|
|
||
|
import (
|
||
|
"crypto/rand"
|
||
|
"crypto/rsa"
|
||
|
"crypto/x509"
|
||
|
"encoding/pem"
|
||
|
"io"
|
||
|
|
||
|
"code.google.com/p/go.crypto/ssh"
|
||
|
"github.com/square/go-jose"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
RSA_BITS = 2048 // Default number of bits in an RSA key
|
||
|
RSA_BITS_MIN = 768 // Minimum number of bits in an RSA key
|
||
|
)
|
||
|
|
||
|
// standard characters allowed in token string.
|
||
|
var chars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
|
||
|
|
||
|
// default token length
|
||
|
var length = 32
|
||
|
|
||
|
// Rand generates a 32-bit random string.
|
||
|
func Rand() string {
|
||
|
b := make([]byte, length)
|
||
|
r := make([]byte, length+(length/4)) // storage for random bytes.
|
||
|
clen := byte(len(chars))
|
||
|
maxrb := byte(256 - (256 % len(chars)))
|
||
|
i := 0
|
||
|
for {
|
||
|
io.ReadFull(rand.Reader, r)
|
||
|
for _, c := range r {
|
||
|
if c >= maxrb {
|
||
|
// Skip this number to avoid modulo bias.
|
||
|
continue
|
||
|
}
|
||
|
b[i] = chars[c%clen]
|
||
|
i++
|
||
|
if i == length {
|
||
|
return string(b)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// helper function to generate an RSA Private Key.
|
||
|
func GeneratePrivateKey() (*rsa.PrivateKey, error) {
|
||
|
return rsa.GenerateKey(rand.Reader, RSA_BITS)
|
||
|
}
|
||
|
|
||
|
// helper function that marshalls an RSA Public Key to an SSH
|
||
|
// .authorized_keys format
|
||
|
func MarshalPublicKey(public *rsa.PublicKey) []byte {
|
||
|
private, err := ssh.NewPublicKey(public)
|
||
|
if err != nil {
|
||
|
return []byte{}
|
||
|
}
|
||
|
|
||
|
return ssh.MarshalAuthorizedKey(private)
|
||
|
}
|
||
|
|
||
|
// helper function that marshalls an RSA Private Key to
|
||
|
// a PEM encoded file.
|
||
|
func MarshalPrivateKey(private *rsa.PrivateKey) []byte {
|
||
|
marshaled := x509.MarshalPKCS1PrivateKey(private)
|
||
|
encoded := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Headers: nil, Bytes: marshaled})
|
||
|
return encoded
|
||
|
}
|
||
|
|
||
|
// UnmarshalPrivateKey is a helper function that unmarshals a PEM
|
||
|
// bytes to an RSA Private Key
|
||
|
func UnmarshalPrivateKey(private []byte) *rsa.PrivateKey {
|
||
|
decoded, _ := pem.Decode(private)
|
||
|
parsed, err := x509.ParsePKCS1PrivateKey(decoded.Bytes)
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
return parsed
|
||
|
}
|
||
|
|
||
|
// Encrypt encrypts a secret string.
|
||
|
func Encrypt(in, privKey string) (string, error) {
|
||
|
rsaPrivKey, err := decodePrivateKey(privKey)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
return encrypt(in, &rsaPrivKey.PublicKey)
|
||
|
}
|
||
|
|
||
|
// decodePrivateKey is a helper function that unmarshals a PEM
|
||
|
// bytes to an RSA Private Key
|
||
|
func decodePrivateKey(privateKey string) (*rsa.PrivateKey, error) {
|
||
|
derBlock, _ := pem.Decode([]byte(privateKey))
|
||
|
return x509.ParsePKCS1PrivateKey(derBlock.Bytes)
|
||
|
}
|
||
|
|
||
|
// encrypt encrypts a plaintext variable using JOSE with
|
||
|
// RSA_OAEP and A128GCM algorithms.
|
||
|
func encrypt(text string, pubKey *rsa.PublicKey) (string, error) {
|
||
|
var encrypted string
|
||
|
var plaintext = []byte(text)
|
||
|
|
||
|
// Creates a new encrypter using defaults
|
||
|
encrypter, err := jose.NewEncrypter(jose.RSA_OAEP, jose.A128GCM, pubKey)
|
||
|
if err != nil {
|
||
|
return encrypted, err
|
||
|
}
|
||
|
// Encrypts the plaintext value and serializes
|
||
|
// as a JOSE string.
|
||
|
object, err := encrypter.Encrypt(plaintext)
|
||
|
if err != nil {
|
||
|
return encrypted, err
|
||
|
}
|
||
|
return object.CompactSerialize()
|
||
|
}
|