1// Package passvault manages the vault containing user records on 2// disk. It contains usernames and associated passwords which are 3// stored hashed (with salt) using scrypt. 4// 5// Copyright (c) 2013 CloudFlare, Inc. 6package passvault 7 8import ( 9 "bytes" 10 "crypto/aes" 11 "crypto/ecdsa" 12 "crypto/elliptic" 13 "crypto/rand" 14 "crypto/rsa" 15 "crypto/sha1" 16 "crypto/x509" 17 "encoding/binary" 18 "encoding/json" 19 "errors" 20 "io/ioutil" 21 "math/big" 22 mrand "math/rand" 23 "os" 24 25 "github.com/cloudflare/redoctober/ecdh" 26 "github.com/cloudflare/redoctober/padding" 27 "github.com/cloudflare/redoctober/symcrypt" 28 "golang.org/x/crypto/scrypt" 29) 30 31// Constants for record type 32const ( 33 RSARecord = "RSA" 34 ECCRecord = "ECC" 35) 36 37var DefaultRecordType = RSARecord 38 39// Constants for scrypt 40const ( 41 KEYLENGTH = 16 // 16-byte output from scrypt 42 N = 16384 // Cost parameter 43 R = 8 // Block size 44 P = 1 // Parallelization factor 45 46 DEFAULT_VERSION = 1 47) 48 49type ECPublicKey struct { 50 Curve *elliptic.CurveParams 51 X, Y *big.Int 52} 53 54// toECDSA takes the internal ECPublicKey and returns an equivalent 55// an ecdsa.PublicKey 56func (pk *ECPublicKey) toECDSA() *ecdsa.PublicKey { 57 ecdsaPub := new(ecdsa.PublicKey) 58 ecdsaPub.Curve = pk.Curve 59 ecdsaPub.X = pk.X 60 ecdsaPub.Y = pk.Y 61 62 return ecdsaPub 63} 64 65// PasswordRecord is the structure used to store password and key 66// material for a single user name. It is written and read from 67// storage in JSON format. 68type PasswordRecord struct { 69 Type string 70 PasswordSalt []byte 71 HashedPassword []byte 72 KeySalt []byte 73 RSAKey struct { 74 RSAExp []byte 75 RSAExpIV []byte 76 RSAPrimeP []byte 77 RSAPrimePIV []byte 78 RSAPrimeQ []byte 79 RSAPrimeQIV []byte 80 RSAPublic rsa.PublicKey 81 } 82 ECKey struct { 83 ECPriv []byte 84 ECPrivIV []byte 85 ECPublic ECPublicKey 86 } 87 AltNames map[string]string 88 Admin bool 89} 90 91// Records is the structure used to read and write a JSON file 92// containing the contents of a password vault 93type Records struct { 94 Version int 95 VaultId int 96 HmacKey []byte 97 Passwords map[string]PasswordRecord 98 99 localPath string // Path of current vault 100} 101 102// Summary is a minmial account summary. 103type Summary struct { 104 Admin bool 105 Type string 106} 107 108func init() { 109 // seed math.random from crypto.random 110 seedBytes, _ := symcrypt.MakeRandom(8) 111 seedBuf := bytes.NewBuffer(seedBytes) 112 n64, _ := binary.ReadVarint(seedBuf) 113 mrand.Seed(n64) 114} 115 116// hashPassword takes a password and derives a scrypt salted and hashed 117// version 118func hashPassword(password string, salt []byte) ([]byte, error) { 119 return scrypt.Key([]byte(password), salt, N, R, P, KEYLENGTH) 120} 121 122// encryptRSARecord takes an RSA private key and encrypts it with 123// a password key 124func encryptRSARecord(newRec *PasswordRecord, rsaPriv *rsa.PrivateKey, passKey []byte) (err error) { 125 if newRec.RSAKey.RSAExpIV, err = symcrypt.MakeRandom(16); err != nil { 126 return 127 } 128 129 paddedExponent := padding.AddPadding(rsaPriv.D.Bytes()) 130 if newRec.RSAKey.RSAExp, err = symcrypt.EncryptCBC(paddedExponent, newRec.RSAKey.RSAExpIV, passKey); err != nil { 131 return 132 } 133 134 if newRec.RSAKey.RSAPrimePIV, err = symcrypt.MakeRandom(16); err != nil { 135 return 136 } 137 138 paddedPrimeP := padding.AddPadding(rsaPriv.Primes[0].Bytes()) 139 if newRec.RSAKey.RSAPrimeP, err = symcrypt.EncryptCBC(paddedPrimeP, newRec.RSAKey.RSAPrimePIV, passKey); err != nil { 140 return 141 } 142 143 if newRec.RSAKey.RSAPrimeQIV, err = symcrypt.MakeRandom(16); err != nil { 144 return 145 } 146 147 paddedPrimeQ := padding.AddPadding(rsaPriv.Primes[1].Bytes()) 148 newRec.RSAKey.RSAPrimeQ, err = symcrypt.EncryptCBC(paddedPrimeQ, newRec.RSAKey.RSAPrimeQIV, passKey) 149 return 150} 151 152// encryptECCRecord takes an ECDSA private key and encrypts it with 153// a password key. 154func encryptECCRecord(newRec *PasswordRecord, ecPriv *ecdsa.PrivateKey, passKey []byte) (err error) { 155 ecX509, err := x509.MarshalECPrivateKey(ecPriv) 156 if err != nil { 157 return 158 } 159 160 if newRec.ECKey.ECPrivIV, err = symcrypt.MakeRandom(16); err != nil { 161 return 162 } 163 164 paddedX509 := padding.AddPadding(ecX509) 165 newRec.ECKey.ECPriv, err = symcrypt.EncryptCBC(paddedX509, newRec.ECKey.ECPrivIV, passKey) 166 return 167} 168 169// createPasswordRec creates a new record from a username and password 170func createPasswordRec(password string, admin bool, userType string) (newRec PasswordRecord, err error) { 171 newRec.Type = userType 172 173 if newRec.PasswordSalt, err = symcrypt.MakeRandom(16); err != nil { 174 return 175 } 176 177 if newRec.HashedPassword, err = hashPassword(password, newRec.PasswordSalt); err != nil { 178 return 179 } 180 181 if newRec.KeySalt, err = symcrypt.MakeRandom(16); err != nil { 182 return 183 } 184 185 passKey, err := derivePasswordKey(password, newRec.KeySalt) 186 if err != nil { 187 return 188 } 189 190 newRec.AltNames = make(map[string]string) 191 192 // generate a key pair 193 switch userType { 194 case RSARecord: 195 var rsaPriv *rsa.PrivateKey 196 rsaPriv, err = rsa.GenerateKey(rand.Reader, 2048) 197 if err != nil { 198 return 199 } 200 // encrypt RSA key with password key 201 if err = encryptRSARecord(&newRec, rsaPriv, passKey); err != nil { 202 return 203 } 204 newRec.RSAKey.RSAPublic = rsaPriv.PublicKey 205 case ECCRecord: 206 var ecPriv *ecdsa.PrivateKey 207 ecPriv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 208 if err != nil { 209 return 210 } 211 // encrypt ECDSA key with password key 212 if err = encryptECCRecord(&newRec, ecPriv, passKey); err != nil { 213 return 214 } 215 newRec.ECKey.ECPublic.Curve = ecPriv.PublicKey.Curve.Params() 216 newRec.ECKey.ECPublic.X = ecPriv.PublicKey.X 217 newRec.ECKey.ECPublic.Y = ecPriv.PublicKey.Y 218 default: 219 err = errors.New("Unknown record type") 220 } 221 222 newRec.Admin = admin 223 224 return 225} 226 227// derivePasswordKey generates a key from a password (and salt) using 228// scrypt 229func derivePasswordKey(password string, keySalt []byte) ([]byte, error) { 230 return scrypt.Key([]byte(password), keySalt, N, R, P, KEYLENGTH) 231} 232 233// decryptECB decrypts bytes using a key in AES ECB mode. 234func decryptECB(data, key []byte) (decryptedData []byte, err error) { 235 aesCrypt, err := aes.NewCipher(key) 236 if err != nil { 237 return 238 } 239 240 decryptedData = make([]byte, len(data)) 241 aesCrypt.Decrypt(decryptedData, data) 242 243 return 244} 245 246// encryptECB encrypts bytes using a key in AES ECB mode. 247func encryptECB(data, key []byte) (encryptedData []byte, err error) { 248 aesCrypt, err := aes.NewCipher(key) 249 if err != nil { 250 return 251 } 252 253 encryptedData = make([]byte, len(data)) 254 aesCrypt.Encrypt(encryptedData, data) 255 256 return 257} 258 259// InitFrom reads the record from disk and initialize global context. 260func InitFrom(path string) (records Records, err error) { 261 var jsonDiskRecord []byte 262 263 if path != "memory" { 264 jsonDiskRecord, err = ioutil.ReadFile(path) 265 266 // It's OK for the file to be missing, we'll create it later if 267 // anything is added. 268 269 if err != nil && !os.IsNotExist(err) { 270 return 271 } 272 } 273 274 // Initialized so that we can determine later if anything was read 275 // from the file. 276 277 records.Version = 0 278 if len(jsonDiskRecord) != 0 { 279 if err = json.Unmarshal(jsonDiskRecord, &records); err != nil { 280 return 281 } 282 } 283 284 err = errors.New("Format error") 285 for k, rec := range records.Passwords { 286 287 if rec.AltNames == nil { 288 rec.AltNames = make(map[string]string) 289 records.Passwords[k] = rec 290 } 291 if len(rec.PasswordSalt) != 16 { 292 return 293 } 294 if len(rec.HashedPassword) != 16 { 295 return 296 } 297 if len(rec.KeySalt) != 16 { 298 return 299 } 300 if rec.Type == RSARecord { 301 if len(rec.RSAKey.RSAExp) == 0 || len(rec.RSAKey.RSAExp)%16 != 0 { 302 return 303 } 304 if len(rec.RSAKey.RSAPrimeP) == 0 || len(rec.RSAKey.RSAPrimeP)%16 != 0 { 305 return 306 } 307 if len(rec.RSAKey.RSAPrimeQ) == 0 || len(rec.RSAKey.RSAPrimeQ)%16 != 0 { 308 return 309 } 310 if len(rec.RSAKey.RSAExpIV) != 16 { 311 return 312 } 313 if len(rec.RSAKey.RSAPrimePIV) != 16 { 314 return 315 } 316 if len(rec.RSAKey.RSAPrimeQIV) != 16 { 317 return 318 } 319 } 320 if rec.Type == ECCRecord { 321 if len(rec.ECKey.ECPriv) == 0 || len(rec.ECKey.ECPriv)%16 != 0 { 322 return 323 } 324 if len(rec.ECKey.ECPrivIV) != 16 { 325 return 326 } 327 } 328 } 329 330 // If the Version field is 0 then it indicates that nothing was 331 // read from the file and so it needs to be initialized. 332 333 if records.Version == 0 { 334 records.Version = DEFAULT_VERSION 335 records.VaultId = int(mrand.Int31()) 336 records.HmacKey, err = symcrypt.MakeRandom(16) 337 if err != nil { 338 return 339 } 340 records.Passwords = make(map[string]PasswordRecord) 341 } 342 343 records.localPath = path 344 345 err = nil 346 return 347} 348 349// WriteRecordsToDisk saves the current state of the records to disk. 350func (records *Records) WriteRecordsToDisk() error { 351 if records.localPath == "memory" { 352 return nil 353 } 354 355 jsonDiskRecord, err := json.Marshal(records) 356 if err != nil { 357 return err 358 } 359 return ioutil.WriteFile(records.localPath, jsonDiskRecord, 0644) 360} 361 362// AddNewRecord adds a new record for a given username and password. 363func (records *Records) AddNewRecord(name, password string, admin bool, userType string) (PasswordRecord, error) { 364 pr, err := createPasswordRec(password, admin, userType) 365 if err != nil { 366 return pr, err 367 } 368 records.SetRecord(pr, name) 369 return pr, records.WriteRecordsToDisk() 370} 371 372// ChangePassword changes the password for a given user. 373func (records *Records) ChangePassword(name, password, newPassword, hipchatName string) (err error) { 374 pr, ok := records.GetRecord(name) 375 376 if !ok { 377 err = errors.New("Record not present") 378 return 379 } 380 381 if len(hipchatName) != 0 { 382 pr.AltNames["HipchatName"] = hipchatName 383 } 384 385 if len(newPassword) == 0 { 386 records.SetRecord(pr, name) 387 return records.WriteRecordsToDisk() 388 } 389 390 var keySalt []byte 391 if keySalt, err = symcrypt.MakeRandom(16); err != nil { 392 return 393 } 394 newPassKey, err := derivePasswordKey(newPassword, keySalt) 395 if err != nil { 396 return 397 } 398 399 // decrypt with old password and re-encrypt original key with new password 400 if pr.Type == RSARecord { 401 var rsaKey rsa.PrivateKey 402 rsaKey, err = pr.GetKeyRSA(password) 403 if err != nil { 404 return 405 } 406 407 // encrypt RSA key with password key 408 err = encryptRSARecord(&pr, &rsaKey, newPassKey) 409 if err != nil { 410 return 411 } 412 } else if pr.Type == ECCRecord { 413 var ecKey *ecdsa.PrivateKey 414 ecKey, err = pr.GetKeyECC(password) 415 if err != nil { 416 return 417 } 418 419 // encrypt ECDSA key with password key 420 err = encryptECCRecord(&pr, ecKey, newPassKey) 421 if err != nil { 422 return 423 } 424 } else { 425 err = errors.New("Unknown record type") 426 return 427 } 428 429 // add the password salt and hash 430 if pr.PasswordSalt, err = symcrypt.MakeRandom(16); err != nil { 431 return 432 } 433 if pr.HashedPassword, err = hashPassword(newPassword, pr.PasswordSalt); err != nil { 434 return 435 } 436 437 pr.KeySalt = keySalt 438 439 records.SetRecord(pr, name) 440 441 return records.WriteRecordsToDisk() 442} 443 444// DeleteRecord deletes a given record. 445func (records *Records) DeleteRecord(name string) error { 446 if _, ok := records.GetRecord(name); ok { 447 delete(records.Passwords, name) 448 return records.WriteRecordsToDisk() 449 } 450 return errors.New("Record missing") 451} 452 453// RevokeRecord removes admin status from a record. 454func (records *Records) RevokeRecord(name string) error { 455 if rec, ok := records.GetRecord(name); ok { 456 rec.Admin = false 457 records.SetRecord(rec, name) 458 return records.WriteRecordsToDisk() 459 } 460 return errors.New("Record missing") 461} 462 463// MakeAdmin adds admin status to a given record. 464func (records *Records) MakeAdmin(name string) error { 465 if rec, ok := records.GetRecord(name); ok { 466 rec.Admin = true 467 records.SetRecord(rec, name) 468 return records.WriteRecordsToDisk() 469 } 470 return errors.New("Record missing") 471} 472 473// SetRecord puts a record into the global status. 474func (records *Records) SetRecord(pr PasswordRecord, name string) { 475 records.Passwords[name] = pr 476} 477 478// GetRecord returns a record given a name. 479func (records *Records) GetRecord(name string) (PasswordRecord, bool) { 480 dpr, found := records.Passwords[name] 481 return dpr, found 482} 483 484// GetVaultID returns the id of the current vault. 485func (records *Records) GetVaultID() (id int, err error) { 486 return records.VaultId, nil 487} 488 489// GetHMACKey returns the hmac key of the current vault. 490func (records *Records) GetHMACKey() (key []byte, err error) { 491 return records.HmacKey, nil 492} 493 494// NumRecords returns the number of records in the vault. 495func (records *Records) NumRecords() int { 496 return len(records.Passwords) 497} 498 499// GetSummary returns a summary of the records on disk. 500func (records *Records) GetSummary() (summary map[string]Summary) { 501 summary = make(map[string]Summary) 502 for name, pass := range records.Passwords { 503 summary[name] = Summary{pass.Admin, pass.Type} 504 } 505 return 506} 507 508// IsAdmin returns the admin status of the PasswordRecord. 509func (pr *PasswordRecord) IsAdmin() bool { 510 return pr.Admin 511} 512 513// GetType returns the type status of the PasswordRecord. 514func (pr *PasswordRecord) GetType() string { 515 return pr.Type 516} 517 518// EncryptKey encrypts a 16-byte key with the RSA or EC key of the record. 519func (pr *PasswordRecord) EncryptKey(in []byte) (out []byte, err error) { 520 if pr.Type == RSARecord { 521 return rsa.EncryptOAEP(sha1.New(), rand.Reader, &pr.RSAKey.RSAPublic, in, nil) 522 } else if pr.Type == ECCRecord { 523 return ecdh.Encrypt(pr.ECKey.ECPublic.toECDSA(), in) 524 } else { 525 return nil, errors.New("Invalid function for record type") 526 } 527} 528 529// GetKeyRSAPub returns the RSA public key of the record. 530func (pr *PasswordRecord) GetKeyRSAPub() (out *rsa.PublicKey, err error) { 531 if pr.Type != RSARecord { 532 return out, errors.New("Invalid function for record type") 533 } 534 return &pr.RSAKey.RSAPublic, err 535} 536 537// GetKeyECCPub returns the ECDSA public key out of the record. 538func (pr *PasswordRecord) GetKeyECCPub() (out *ecdsa.PublicKey, err error) { 539 if pr.Type != ECCRecord { 540 return out, errors.New("Invalid function for record type") 541 } 542 return pr.ECKey.ECPublic.toECDSA(), err 543} 544 545// GetKeyECC returns the ECDSA private key of the record given the correct password. 546func (pr *PasswordRecord) GetKeyECC(password string) (key *ecdsa.PrivateKey, err error) { 547 if pr.Type != ECCRecord { 548 return key, errors.New("Invalid function for record type") 549 } 550 551 if err = pr.ValidatePassword(password); err != nil { 552 return 553 } 554 555 passKey, err := derivePasswordKey(password, pr.KeySalt) 556 if err != nil { 557 return 558 } 559 560 x509Padded, err := symcrypt.DecryptCBC(pr.ECKey.ECPriv, pr.ECKey.ECPrivIV, passKey) 561 if err != nil { 562 return 563 } 564 565 ecX509, err := padding.RemovePadding(x509Padded) 566 if err != nil { 567 return 568 } 569 return x509.ParseECPrivateKey(ecX509) 570} 571 572// GetKeyRSA returns the RSA private key of the record given the correct password. 573func (pr *PasswordRecord) GetKeyRSA(password string) (key rsa.PrivateKey, err error) { 574 if pr.Type != RSARecord { 575 return key, errors.New("Invalid function for record type") 576 } 577 578 err = pr.ValidatePassword(password) 579 if err != nil { 580 return 581 } 582 583 passKey, err := derivePasswordKey(password, pr.KeySalt) 584 if err != nil { 585 return 586 } 587 588 rsaExponentPadded, err := symcrypt.DecryptCBC(pr.RSAKey.RSAExp, pr.RSAKey.RSAExpIV, passKey) 589 if err != nil { 590 return 591 } 592 rsaExponent, err := padding.RemovePadding(rsaExponentPadded) 593 if err != nil { 594 return 595 } 596 597 rsaPrimePPadded, err := symcrypt.DecryptCBC(pr.RSAKey.RSAPrimeP, pr.RSAKey.RSAPrimePIV, passKey) 598 if err != nil { 599 return 600 } 601 rsaPrimeP, err := padding.RemovePadding(rsaPrimePPadded) 602 if err != nil { 603 return 604 } 605 606 rsaPrimeQPadded, err := symcrypt.DecryptCBC(pr.RSAKey.RSAPrimeQ, pr.RSAKey.RSAPrimeQIV, passKey) 607 if err != nil { 608 return 609 } 610 rsaPrimeQ, err := padding.RemovePadding(rsaPrimeQPadded) 611 if err != nil { 612 return 613 } 614 615 key.PublicKey = pr.RSAKey.RSAPublic 616 key.D = big.NewInt(0).SetBytes(rsaExponent) 617 key.Primes = []*big.Int{big.NewInt(0), big.NewInt(0)} 618 key.Primes[0].SetBytes(rsaPrimeP) 619 key.Primes[1].SetBytes(rsaPrimeQ) 620 621 err = key.Validate() 622 if err != nil { 623 return 624 } 625 626 return 627} 628func (records *Records) GetAltNameFromName(alt, name string) (altName string, found bool) { 629 if passwordRecord, ok := records.Passwords[name]; ok { 630 if altName, ok := passwordRecord.AltNames[alt]; ok { 631 return altName, true 632 } 633 } 634 return "", false 635} 636func (r *Records) GetAltNamesFromName(alt string, names []string) map[string]string { 637 altNames := make(map[string]string) 638 for _, name := range names { 639 altName, found := r.GetAltNameFromName(alt, name) 640 if !found { 641 altName = name 642 } 643 altNames[name] = altName 644 } 645 return altNames 646 647} 648 649// ValidatePassword returns an error if the password is incorrect. 650func (pr *PasswordRecord) ValidatePassword(password string) error { 651 h, err := hashPassword(password, pr.PasswordSalt) 652 if err != nil { 653 return err 654 } 655 656 if bytes.Compare(h, pr.HashedPassword) != 0 { 657 return errors.New("Wrong Password") 658 } 659 return nil 660} 661