...

Source file src/golang.org/x/crypto/openpgp/s2k/s2k.go

Documentation: golang.org/x/crypto/openpgp/s2k

     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 s2k implements the various OpenPGP string-to-key transforms as
     6  // specified in RFC 4800 section 3.7.1.
     7  //
     8  // Deprecated: this package is unmaintained except for security fixes. New
     9  // applications should consider a more focused, modern alternative to OpenPGP
    10  // for their specific task. If you are required to interoperate with OpenPGP
    11  // systems and need a maintained package, consider a community fork.
    12  // See https://golang.org/issue/44226.
    13  package s2k // import "golang.org/x/crypto/openpgp/s2k"
    14  
    15  import (
    16  	"crypto"
    17  	"hash"
    18  	"io"
    19  	"strconv"
    20  
    21  	"golang.org/x/crypto/openpgp/errors"
    22  )
    23  
    24  // Config collects configuration parameters for s2k key-stretching
    25  // transformatioms. A nil *Config is valid and results in all default
    26  // values. Currently, Config is used only by the Serialize function in
    27  // this package.
    28  type Config struct {
    29  	// Hash is the default hash function to be used. If
    30  	// nil, SHA1 is used.
    31  	Hash crypto.Hash
    32  	// S2KCount is only used for symmetric encryption. It
    33  	// determines the strength of the passphrase stretching when
    34  	// the said passphrase is hashed to produce a key. S2KCount
    35  	// should be between 1024 and 65011712, inclusive. If Config
    36  	// is nil or S2KCount is 0, the value 65536 used. Not all
    37  	// values in the above range can be represented. S2KCount will
    38  	// be rounded up to the next representable value if it cannot
    39  	// be encoded exactly. When set, it is strongly encrouraged to
    40  	// use a value that is at least 65536. See RFC 4880 Section
    41  	// 3.7.1.3.
    42  	S2KCount int
    43  }
    44  
    45  func (c *Config) hash() crypto.Hash {
    46  	if c == nil || uint(c.Hash) == 0 {
    47  		// SHA1 is the historical default in this package.
    48  		return crypto.SHA1
    49  	}
    50  
    51  	return c.Hash
    52  }
    53  
    54  func (c *Config) encodedCount() uint8 {
    55  	if c == nil || c.S2KCount == 0 {
    56  		return 96 // The common case. Correspoding to 65536
    57  	}
    58  
    59  	i := c.S2KCount
    60  	switch {
    61  	// Behave like GPG. Should we make 65536 the lowest value used?
    62  	case i < 1024:
    63  		i = 1024
    64  	case i > 65011712:
    65  		i = 65011712
    66  	}
    67  
    68  	return encodeCount(i)
    69  }
    70  
    71  // encodeCount converts an iterative "count" in the range 1024 to
    72  // 65011712, inclusive, to an encoded count. The return value is the
    73  // octet that is actually stored in the GPG file. encodeCount panics
    74  // if i is not in the above range (encodedCount above takes care to
    75  // pass i in the correct range). See RFC 4880 Section 3.7.7.1.
    76  func encodeCount(i int) uint8 {
    77  	if i < 1024 || i > 65011712 {
    78  		panic("count arg i outside the required range")
    79  	}
    80  
    81  	for encoded := 0; encoded < 256; encoded++ {
    82  		count := decodeCount(uint8(encoded))
    83  		if count >= i {
    84  			return uint8(encoded)
    85  		}
    86  	}
    87  
    88  	return 255
    89  }
    90  
    91  // decodeCount returns the s2k mode 3 iterative "count" corresponding to
    92  // the encoded octet c.
    93  func decodeCount(c uint8) int {
    94  	return (16 + int(c&15)) << (uint32(c>>4) + 6)
    95  }
    96  
    97  // Simple writes to out the result of computing the Simple S2K function (RFC
    98  // 4880, section 3.7.1.1) using the given hash and input passphrase.
    99  func Simple(out []byte, h hash.Hash, in []byte) {
   100  	Salted(out, h, in, nil)
   101  }
   102  
   103  var zero [1]byte
   104  
   105  // Salted writes to out the result of computing the Salted S2K function (RFC
   106  // 4880, section 3.7.1.2) using the given hash, input passphrase and salt.
   107  func Salted(out []byte, h hash.Hash, in []byte, salt []byte) {
   108  	done := 0
   109  	var digest []byte
   110  
   111  	for i := 0; done < len(out); i++ {
   112  		h.Reset()
   113  		for j := 0; j < i; j++ {
   114  			h.Write(zero[:])
   115  		}
   116  		h.Write(salt)
   117  		h.Write(in)
   118  		digest = h.Sum(digest[:0])
   119  		n := copy(out[done:], digest)
   120  		done += n
   121  	}
   122  }
   123  
   124  // Iterated writes to out the result of computing the Iterated and Salted S2K
   125  // function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
   126  // salt and iteration count.
   127  func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
   128  	combined := make([]byte, len(in)+len(salt))
   129  	copy(combined, salt)
   130  	copy(combined[len(salt):], in)
   131  
   132  	if count < len(combined) {
   133  		count = len(combined)
   134  	}
   135  
   136  	done := 0
   137  	var digest []byte
   138  	for i := 0; done < len(out); i++ {
   139  		h.Reset()
   140  		for j := 0; j < i; j++ {
   141  			h.Write(zero[:])
   142  		}
   143  		written := 0
   144  		for written < count {
   145  			if written+len(combined) > count {
   146  				todo := count - written
   147  				h.Write(combined[:todo])
   148  				written = count
   149  			} else {
   150  				h.Write(combined)
   151  				written += len(combined)
   152  			}
   153  		}
   154  		digest = h.Sum(digest[:0])
   155  		n := copy(out[done:], digest)
   156  		done += n
   157  	}
   158  }
   159  
   160  // Parse reads a binary specification for a string-to-key transformation from r
   161  // and returns a function which performs that transform.
   162  func Parse(r io.Reader) (f func(out, in []byte), err error) {
   163  	var buf [9]byte
   164  
   165  	_, err = io.ReadFull(r, buf[:2])
   166  	if err != nil {
   167  		return
   168  	}
   169  
   170  	hash, ok := HashIdToHash(buf[1])
   171  	if !ok {
   172  		return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1])))
   173  	}
   174  	if !hash.Available() {
   175  		return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hash)))
   176  	}
   177  	h := hash.New()
   178  
   179  	switch buf[0] {
   180  	case 0:
   181  		f := func(out, in []byte) {
   182  			Simple(out, h, in)
   183  		}
   184  		return f, nil
   185  	case 1:
   186  		_, err = io.ReadFull(r, buf[:8])
   187  		if err != nil {
   188  			return
   189  		}
   190  		f := func(out, in []byte) {
   191  			Salted(out, h, in, buf[:8])
   192  		}
   193  		return f, nil
   194  	case 3:
   195  		_, err = io.ReadFull(r, buf[:9])
   196  		if err != nil {
   197  			return
   198  		}
   199  		count := decodeCount(buf[8])
   200  		f := func(out, in []byte) {
   201  			Iterated(out, h, in, buf[:8], count)
   202  		}
   203  		return f, nil
   204  	}
   205  
   206  	return nil, errors.UnsupportedError("S2K function")
   207  }
   208  
   209  // Serialize salts and stretches the given passphrase and writes the
   210  // resulting key into key. It also serializes an S2K descriptor to
   211  // w. The key stretching can be configured with c, which may be
   212  // nil. In that case, sensible defaults will be used.
   213  func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error {
   214  	var buf [11]byte
   215  	buf[0] = 3 /* iterated and salted */
   216  	buf[1], _ = HashToHashId(c.hash())
   217  	salt := buf[2:10]
   218  	if _, err := io.ReadFull(rand, salt); err != nil {
   219  		return err
   220  	}
   221  	encodedCount := c.encodedCount()
   222  	count := decodeCount(encodedCount)
   223  	buf[10] = encodedCount
   224  	if _, err := w.Write(buf[:]); err != nil {
   225  		return err
   226  	}
   227  
   228  	Iterated(key, c.hash().New(), passphrase, salt, count)
   229  	return nil
   230  }
   231  
   232  // hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with
   233  // Go's crypto.Hash type. See RFC 4880, section 9.4.
   234  var hashToHashIdMapping = []struct {
   235  	id   byte
   236  	hash crypto.Hash
   237  	name string
   238  }{
   239  	{1, crypto.MD5, "MD5"},
   240  	{2, crypto.SHA1, "SHA1"},
   241  	{3, crypto.RIPEMD160, "RIPEMD160"},
   242  	{8, crypto.SHA256, "SHA256"},
   243  	{9, crypto.SHA384, "SHA384"},
   244  	{10, crypto.SHA512, "SHA512"},
   245  	{11, crypto.SHA224, "SHA224"},
   246  }
   247  
   248  // HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
   249  // hash id.
   250  func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
   251  	for _, m := range hashToHashIdMapping {
   252  		if m.id == id {
   253  			return m.hash, true
   254  		}
   255  	}
   256  	return 0, false
   257  }
   258  
   259  // HashIdToString returns the name of the hash function corresponding to the
   260  // given OpenPGP hash id.
   261  func HashIdToString(id byte) (name string, ok bool) {
   262  	for _, m := range hashToHashIdMapping {
   263  		if m.id == id {
   264  			return m.name, true
   265  		}
   266  	}
   267  
   268  	return "", false
   269  }
   270  
   271  // HashToHashId returns an OpenPGP hash id which corresponds the given Hash.
   272  func HashToHashId(h crypto.Hash) (id byte, ok bool) {
   273  	for _, m := range hashToHashIdMapping {
   274  		if m.hash == h {
   275  			return m.id, true
   276  		}
   277  	}
   278  	return 0, false
   279  }
   280  

View as plain text