summaryrefslogtreecommitdiffstats
path: root/chromium/sync/internal_api/sync_encryption_handler_impl.cc
blob: 34bf0335c8f6b31dbb010f1faf0472643442f665 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sync/internal_api/sync_encryption_handler_impl.h"

#include <queue>
#include <string>

#include "base/base64.h"
#include "base/bind.h"
#include "base/json/json_string_value_serializer.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/time/time.h"
#include "base/tracked_objects.h"
#include "sync/internal_api/public/read_node.h"
#include "sync/internal_api/public/read_transaction.h"
#include "sync/internal_api/public/user_share.h"
#include "sync/internal_api/public/util/experiments.h"
#include "sync/internal_api/public/util/sync_string_conversions.h"
#include "sync/internal_api/public/write_node.h"
#include "sync/internal_api/public/write_transaction.h"
#include "sync/protocol/encryption.pb.h"
#include "sync/protocol/nigori_specifics.pb.h"
#include "sync/protocol/sync.pb.h"
#include "sync/syncable/directory.h"
#include "sync/syncable/entry.h"
#include "sync/syncable/nigori_util.h"
#include "sync/syncable/syncable_base_transaction.h"
#include "sync/util/cryptographer.h"
#include "sync/util/encryptor.h"
#include "sync/util/time.h"

namespace syncer {

namespace {

// The maximum number of times we will automatically overwrite the nigori node
// because the encryption keys don't match (per chrome instantiation).
// We protect ourselves against nigori rollbacks, but it's possible two
// different clients might have contrasting view of what the nigori node state
// should be, in which case they might ping pong (see crbug.com/119207).
static const int kNigoriOverwriteLimit = 10;

// Enumeration of nigori keystore migration results (for use in UMA stats).
enum NigoriMigrationResult {
  FAILED_TO_SET_DEFAULT_KEYSTORE,
  FAILED_TO_SET_NONDEFAULT_KEYSTORE,
  FAILED_TO_EXTRACT_DECRYPTOR,
  FAILED_TO_EXTRACT_KEYBAG,
  MIGRATION_SUCCESS_KEYSTORE_NONDEFAULT,
  MIGRATION_SUCCESS_KEYSTORE_DEFAULT,
  MIGRATION_SUCCESS_FROZEN_IMPLICIT,
  MIGRATION_SUCCESS_CUSTOM,
  MIGRATION_RESULT_SIZE,
};

enum NigoriMigrationState {
  MIGRATED,
  NOT_MIGRATED_CRYPTO_NOT_READY,
  NOT_MIGRATED_NO_KEYSTORE_KEY,
  NOT_MIGRATED_UNKNOWN_REASON,
  MIGRATION_STATE_SIZE,
};

// The new passphrase state is sufficient to determine whether a nigori node
// is migrated to support keystore encryption. In addition though, we also
// want to verify the conditions for proper keystore encryption functionality.
// 1. Passphrase state is set.
// 2. Migration time is set.
// 3. Frozen keybag is true
// 4. If passphrase state is keystore, keystore_decryptor_token is set.
bool IsNigoriMigratedToKeystore(const sync_pb::NigoriSpecifics& nigori) {
  if (!nigori.has_passphrase_type())
    return false;
  if (!nigori.has_keystore_migration_time())
    return false;
  if (!nigori.keybag_is_frozen())
    return false;
  if (nigori.passphrase_type() ==
          sync_pb::NigoriSpecifics::IMPLICIT_PASSPHRASE)
    return false;
  if (nigori.passphrase_type() ==
          sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE &&
      nigori.keystore_decryptor_token().blob().empty())
    return false;
  if (!nigori.has_keystore_migration_time())
    return false;
  return true;
}

PassphraseType ProtoPassphraseTypeToEnum(
    sync_pb::NigoriSpecifics::PassphraseType type) {
  switch(type) {
    case sync_pb::NigoriSpecifics::IMPLICIT_PASSPHRASE:
      return IMPLICIT_PASSPHRASE;
    case sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE:
      return KEYSTORE_PASSPHRASE;
    case sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE:
      return CUSTOM_PASSPHRASE;
    case sync_pb::NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE:
      return FROZEN_IMPLICIT_PASSPHRASE;
    default:
      NOTREACHED();
      return IMPLICIT_PASSPHRASE;
  };
}

sync_pb::NigoriSpecifics::PassphraseType
EnumPassphraseTypeToProto(PassphraseType type) {
  switch(type) {
    case IMPLICIT_PASSPHRASE:
      return sync_pb::NigoriSpecifics::IMPLICIT_PASSPHRASE;
    case KEYSTORE_PASSPHRASE:
      return sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE;
    case CUSTOM_PASSPHRASE:
      return sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE;
    case FROZEN_IMPLICIT_PASSPHRASE:
      return sync_pb::NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE;
    default:
      NOTREACHED();
      return sync_pb::NigoriSpecifics::IMPLICIT_PASSPHRASE;
  };
}

bool IsExplicitPassphrase(PassphraseType type) {
  return type == CUSTOM_PASSPHRASE || type == FROZEN_IMPLICIT_PASSPHRASE;
}

// Keystore Bootstrap Token helper methods.
// The bootstrap is a base64 encoded, encrypted, ListValue of keystore key
// strings, with the current keystore key as the last value in the list.
std::string PackKeystoreBootstrapToken(
    const std::vector<std::string>& old_keystore_keys,
    const std::string& current_keystore_key,
    Encryptor* encryptor) {
  if (current_keystore_key.empty())
    return std::string();

  base::ListValue keystore_key_values;
  for (size_t i = 0; i < old_keystore_keys.size(); ++i)
    keystore_key_values.AppendString(old_keystore_keys[i]);
  keystore_key_values.AppendString(current_keystore_key);

  // Update the bootstrap token.
  // The bootstrap is a base64 encoded, encrypted, ListValue of keystore key
  // strings, with the current keystore key as the last value in the list.
  std::string serialized_keystores;
  JSONStringValueSerializer json(&serialized_keystores);
  json.Serialize(keystore_key_values);
  std::string encrypted_keystores;
  encryptor->EncryptString(serialized_keystores,
                           &encrypted_keystores);
  std::string keystore_bootstrap;
  base::Base64Encode(encrypted_keystores, &keystore_bootstrap);
  return keystore_bootstrap;
}

bool UnpackKeystoreBootstrapToken(
    const std::string& keystore_bootstrap_token,
    Encryptor* encryptor,
    std::vector<std::string>* old_keystore_keys,
    std::string* current_keystore_key) {
  if (keystore_bootstrap_token.empty())
    return false;
  std::string base64_decoded_keystore_bootstrap;
  if (!base::Base64Decode(keystore_bootstrap_token,
                          &base64_decoded_keystore_bootstrap)) {
    return false;
  }
  std::string decrypted_keystore_bootstrap;
  if (!encryptor->DecryptString(base64_decoded_keystore_bootstrap,
                                &decrypted_keystore_bootstrap)) {
    return false;
  }
  JSONStringValueSerializer json(&decrypted_keystore_bootstrap);
  scoped_ptr<base::Value> deserialized_keystore_keys(
      json.Deserialize(NULL, NULL));
  if (!deserialized_keystore_keys)
    return false;
  base::ListValue* internal_list_value = NULL;
  if (!deserialized_keystore_keys->GetAsList(&internal_list_value))
    return false;
  int number_of_keystore_keys = internal_list_value->GetSize();
  if (!internal_list_value->GetString(number_of_keystore_keys - 1,
                                      current_keystore_key)) {
    return false;
  }
  old_keystore_keys->resize(number_of_keystore_keys - 1);
  for (int i = 0; i < number_of_keystore_keys - 1; ++i)
    internal_list_value->GetString(i, &(*old_keystore_keys)[i]);
  return true;
}

}  // namespace

SyncEncryptionHandlerImpl::Vault::Vault(
    Encryptor* encryptor,
    ModelTypeSet encrypted_types)
    : cryptographer(encryptor),
      encrypted_types(encrypted_types) {
}

SyncEncryptionHandlerImpl::Vault::~Vault() {
}

SyncEncryptionHandlerImpl::SyncEncryptionHandlerImpl(
    UserShare* user_share,
    Encryptor* encryptor,
    const std::string& restored_key_for_bootstrapping,
    const std::string& restored_keystore_key_for_bootstrapping)
    : user_share_(user_share),
      vault_unsafe_(encryptor, SensitiveTypes()),
      encrypt_everything_(false),
      passphrase_type_(IMPLICIT_PASSPHRASE),
      nigori_overwrite_count_(0),
      weak_ptr_factory_(this) {
  // Restore the cryptographer's previous keys. Note that we don't add the
  // keystore keys into the cryptographer here, in case a migration was pending.
  vault_unsafe_.cryptographer.Bootstrap(restored_key_for_bootstrapping);

  // If this fails, we won't have a valid keystore key, and will simply request
  // new ones from the server on the next DownloadUpdates.
  UnpackKeystoreBootstrapToken(
      restored_keystore_key_for_bootstrapping,
      encryptor,
      &old_keystore_keys_,
      &keystore_key_);
}

SyncEncryptionHandlerImpl::~SyncEncryptionHandlerImpl() {}

void SyncEncryptionHandlerImpl::AddObserver(Observer* observer) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(!observers_.HasObserver(observer));
  observers_.AddObserver(observer);
}

void SyncEncryptionHandlerImpl::RemoveObserver(Observer* observer) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(observers_.HasObserver(observer));
  observers_.RemoveObserver(observer);
}

void SyncEncryptionHandlerImpl::Init() {
  DCHECK(thread_checker_.CalledOnValidThread());
  WriteTransaction trans(FROM_HERE, user_share_);
  WriteNode node(&trans);

  if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK)
    return;
  if (!ApplyNigoriUpdateImpl(node.GetNigoriSpecifics(),
                             trans.GetWrappedTrans())) {
    WriteEncryptionStateToNigori(&trans);
  }

  bool has_pending_keys = UnlockVault(
      trans.GetWrappedTrans()).cryptographer.has_pending_keys();
  bool is_ready = UnlockVault(
      trans.GetWrappedTrans()).cryptographer.is_ready();
  // Log the state of the cryptographer regardless of migration state.
  UMA_HISTOGRAM_BOOLEAN("Sync.CryptographerReady", is_ready);
  UMA_HISTOGRAM_BOOLEAN("Sync.CryptographerPendingKeys", has_pending_keys);
  if (IsNigoriMigratedToKeystore(node.GetNigoriSpecifics())) {
    // This account has a nigori node that has been migrated to support
    // keystore.
    UMA_HISTOGRAM_ENUMERATION("Sync.NigoriMigrationState",
                              MIGRATED,
                              MIGRATION_STATE_SIZE);
    if (has_pending_keys && passphrase_type_ == KEYSTORE_PASSPHRASE) {
      // If this is happening, it means the keystore decryptor is either
      // undecryptable with the available keystore keys or does not match the
      // nigori keybag's encryption key. Otherwise we're simply missing the
      // keystore key.
      UMA_HISTOGRAM_BOOLEAN("Sync.KeystoreDecryptionFailed",
                            !keystore_key_.empty());
    }
  } else if (!is_ready) {
    // Migration cannot occur until the cryptographer is ready (initialized
    // with GAIA password and any pending keys resolved).
    UMA_HISTOGRAM_ENUMERATION("Sync.NigoriMigrationState",
                              NOT_MIGRATED_CRYPTO_NOT_READY,
                              MIGRATION_STATE_SIZE);
  } else if (keystore_key_.empty()) {
    // The client has no keystore key, either because it is not yet enabled or
    // the server is not sending a valid keystore key.
    UMA_HISTOGRAM_ENUMERATION("Sync.NigoriMigrationState",
                              NOT_MIGRATED_NO_KEYSTORE_KEY,
                              MIGRATION_STATE_SIZE);
  } else {
    // If the above conditions have been met and the nigori node is still not
    // migrated, something failed in the migration process.
    UMA_HISTOGRAM_ENUMERATION("Sync.NigoriMigrationState",
                              NOT_MIGRATED_UNKNOWN_REASON,
                              MIGRATION_STATE_SIZE);
  }


  // Always trigger an encrypted types and cryptographer state change event at
  // init time so observers get the initial values.
  FOR_EACH_OBSERVER(
      Observer, observers_,
      OnEncryptedTypesChanged(
          UnlockVault(trans.GetWrappedTrans()).encrypted_types,
          encrypt_everything_));
  FOR_EACH_OBSERVER(
      SyncEncryptionHandler::Observer,
      observers_,
      OnCryptographerStateChanged(
          &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer));

  // If the cryptographer is not ready (either it has pending keys or we
  // failed to initialize it), we don't want to try and re-encrypt the data.
  // If we had encrypted types, the DataTypeManager will block, preventing
  // sync from happening until the the passphrase is provided.
  if (UnlockVault(trans.GetWrappedTrans()).cryptographer.is_ready())
    ReEncryptEverything(&trans);
}

void SyncEncryptionHandlerImpl::SetEncryptionPassphrase(
    const std::string& passphrase,
    bool is_explicit) {
  DCHECK(thread_checker_.CalledOnValidThread());
  // We do not accept empty passphrases.
  if (passphrase.empty()) {
    NOTREACHED() << "Cannot encrypt with an empty passphrase.";
    return;
  }

  // All accesses to the cryptographer are protected by a transaction.
  WriteTransaction trans(FROM_HERE, user_share_);
  KeyParams key_params = {"localhost", "dummy", passphrase};
  WriteNode node(&trans);
  if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
    NOTREACHED();
    return;
  }

  Cryptographer* cryptographer =
      &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer;

  // Once we've migrated to keystore, the only way to set a passphrase for
  // encryption is to set a custom passphrase.
  if (IsNigoriMigratedToKeystore(node.GetNigoriSpecifics())) {
    if (!is_explicit) {
      DCHECK(cryptographer->is_ready());
      // The user is setting a new implicit passphrase. At this point we don't
      // care, so drop it on the floor. This is safe because if we have a
      // migrated nigori node, then we don't need to create an initial
      // encryption key.
      LOG(WARNING) << "Ignoring new implicit passphrase. Keystore migration "
                   << "already performed.";
      return;
    }
    // Will fail if we already have an explicit passphrase or we have pending
    // keys.
    SetCustomPassphrase(passphrase, &trans, &node);

    // When keystore migration occurs, the "CustomEncryption" UMA stat must be
    // logged as true.
    UMA_HISTOGRAM_BOOLEAN("Sync.CustomEncryption", true);
    return;
  }

  std::string bootstrap_token;
  sync_pb::EncryptedData pending_keys;
  if (cryptographer->has_pending_keys())
    pending_keys = cryptographer->GetPendingKeys();
  bool success = false;

  // There are six cases to handle here:
  // 1. The user has no pending keys and is setting their current GAIA password
  //    as the encryption passphrase. This happens either during first time sync
  //    with a clean profile, or after re-authenticating on a profile that was
  //    already signed in with the cryptographer ready.
  // 2. The user has no pending keys, and is overwriting an (already provided)
  //    implicit passphrase with an explicit (custom) passphrase.
  // 3. The user has pending keys for an explicit passphrase that is somehow set
  //    to their current GAIA passphrase.
  // 4. The user has pending keys encrypted with their current GAIA passphrase
  //    and the caller passes in the current GAIA passphrase.
  // 5. The user has pending keys encrypted with an older GAIA passphrase
  //    and the caller passes in the current GAIA passphrase.
  // 6. The user has previously done encryption with an explicit passphrase.
  // Furthermore, we enforce the fact that the bootstrap encryption token will
  // always be derived from the newest GAIA password if the account is using
  // an implicit passphrase (even if the data is encrypted with an old GAIA
  // password). If the account is using an explicit (custom) passphrase, the
  // bootstrap token will be derived from the most recently provided explicit
  // passphrase (that was able to decrypt the data).
  if (!IsExplicitPassphrase(passphrase_type_)) {
    if (!cryptographer->has_pending_keys()) {
      if (cryptographer->AddKey(key_params)) {
        // Case 1 and 2. We set a new GAIA passphrase when there are no pending
        // keys (1), or overwriting an implicit passphrase with a new explicit
        // one (2) when there are no pending keys.
        if (is_explicit) {
          DVLOG(1) << "Setting explicit passphrase for encryption.";
          passphrase_type_ = CUSTOM_PASSPHRASE;
          custom_passphrase_time_ = base::Time::Now();
          FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                            OnPassphraseTypeChanged(
                                passphrase_type_,
                                GetExplicitPassphraseTime()));
        } else {
          DVLOG(1) << "Setting implicit passphrase for encryption.";
        }
        cryptographer->GetBootstrapToken(&bootstrap_token);

        // With M26, sync accounts can be in only one of two encryption states:
        // 1) Encrypt only passwords with an implicit passphrase.
        // 2) Encrypt all sync datatypes with an explicit passphrase.
        // We deprecate the "EncryptAllData" and "CustomPassphrase" histograms,
        // and keep track of an account's encryption state via the
        // "CustomEncryption" histogram. See http://crbug.com/131478.
        UMA_HISTOGRAM_BOOLEAN("Sync.CustomEncryption", is_explicit);

        success = true;
      } else {
        NOTREACHED() << "Failed to add key to cryptographer.";
        success = false;
      }
    } else {  // cryptographer->has_pending_keys() == true
      if (is_explicit) {
        // This can only happen if the nigori node is updated with a new
        // implicit passphrase while a client is attempting to set a new custom
        // passphrase (race condition).
        DVLOG(1) << "Failing because an implicit passphrase is already set.";
        success = false;
      } else {  // is_explicit == false
        if (cryptographer->DecryptPendingKeys(key_params)) {
          // Case 4. We successfully decrypted with the implicit GAIA passphrase
          // passed in.
          DVLOG(1) << "Implicit internal passphrase accepted for decryption.";
          cryptographer->GetBootstrapToken(&bootstrap_token);
          success = true;
        } else {
          // Case 5. Encryption was done with an old GAIA password, but we were
          // provided with the current GAIA password. We need to generate a new
          // bootstrap token to preserve it. We build a temporary cryptographer
          // to allow us to extract these params without polluting our current
          // cryptographer.
          DVLOG(1) << "Implicit internal passphrase failed to decrypt, adding "
                   << "anyways as default passphrase and persisting via "
                   << "bootstrap token.";
          Cryptographer temp_cryptographer(cryptographer->encryptor());
          temp_cryptographer.AddKey(key_params);
          temp_cryptographer.GetBootstrapToken(&bootstrap_token);
          // We then set the new passphrase as the default passphrase of the
          // real cryptographer, even though we have pending keys. This is safe,
          // as although Cryptographer::is_initialized() will now be true,
          // is_ready() will remain false due to having pending keys.
          cryptographer->AddKey(key_params);
          success = false;
        }
      }  // is_explicit
    }  // cryptographer->has_pending_keys()
  } else {  // IsExplicitPassphrase(passphrase_type_) == true.
    // Case 6. We do not want to override a previously set explicit passphrase,
    // so we return a failure.
    DVLOG(1) << "Failing because an explicit passphrase is already set.";
    success = false;
  }

  DVLOG_IF(1, !success)
      << "Failure in SetEncryptionPassphrase; notifying and returning.";
  DVLOG_IF(1, success)
      << "Successfully set encryption passphrase; updating nigori and "
         "reencrypting.";

  FinishSetPassphrase(success, bootstrap_token, &trans, &node);
}

void SyncEncryptionHandlerImpl::SetDecryptionPassphrase(
    const std::string& passphrase) {
  DCHECK(thread_checker_.CalledOnValidThread());
  // We do not accept empty passphrases.
  if (passphrase.empty()) {
    NOTREACHED() << "Cannot decrypt with an empty passphrase.";
    return;
  }

  // All accesses to the cryptographer are protected by a transaction.
  WriteTransaction trans(FROM_HERE, user_share_);
  KeyParams key_params = {"localhost", "dummy", passphrase};
  WriteNode node(&trans);
  if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
    NOTREACHED();
    return;
  }

  // Once we've migrated to keystore, we're only ever decrypting keys derived
  // from an explicit passphrase. But, for clients without a keystore key yet
  // (either not on by default or failed to download one), we still support
  // decrypting with a gaia passphrase, and therefore bypass the
  // DecryptPendingKeysWithExplicitPassphrase logic.
  if (IsNigoriMigratedToKeystore(node.GetNigoriSpecifics()) &&
      IsExplicitPassphrase(passphrase_type_)) {
    DecryptPendingKeysWithExplicitPassphrase(passphrase, &trans, &node);
    return;
  }

  Cryptographer* cryptographer =
      &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer;
  if (!cryptographer->has_pending_keys()) {
    // Note that this *can* happen in a rare situation where data is
    // re-encrypted on another client while a SetDecryptionPassphrase() call is
    // in-flight on this client. It is rare enough that we choose to do nothing.
    NOTREACHED() << "Attempt to set decryption passphrase failed because there "
                 << "were no pending keys.";
    return;
  }

  std::string bootstrap_token;
  sync_pb::EncryptedData pending_keys;
  pending_keys = cryptographer->GetPendingKeys();
  bool success = false;

  // There are three cases to handle here:
  // 7. We're using the current GAIA password to decrypt the pending keys. This
  //    happens when signing in to an account with a previously set implicit
  //    passphrase, where the data is already encrypted with the newest GAIA
  //    password.
  // 8. The user is providing an old GAIA password to decrypt the pending keys.
  //    In this case, the user is using an implicit passphrase, but has changed
  //    their password since they last encrypted their data, and therefore
  //    their current GAIA password was unable to decrypt the data. This will
  //    happen when the user is setting up a new profile with a previously
  //    encrypted account (after changing passwords).
  // 9. The user is providing a previously set explicit passphrase to decrypt
  //    the pending keys.
  if (!IsExplicitPassphrase(passphrase_type_)) {
    if (cryptographer->is_initialized()) {
      // We only want to change the default encryption key to the pending
      // one if the pending keybag already contains the current default.
      // This covers the case where a different client re-encrypted
      // everything with a newer gaia passphrase (and hence the keybag
      // contains keys from all previously used gaia passphrases).
      // Otherwise, we're in a situation where the pending keys are
      // encrypted with an old gaia passphrase, while the default is the
      // current gaia passphrase. In that case, we preserve the default.
      Cryptographer temp_cryptographer(cryptographer->encryptor());
      temp_cryptographer.SetPendingKeys(cryptographer->GetPendingKeys());
      if (temp_cryptographer.DecryptPendingKeys(key_params)) {
        // Check to see if the pending bag of keys contains the current
        // default key.
        sync_pb::EncryptedData encrypted;
        cryptographer->GetKeys(&encrypted);
        if (temp_cryptographer.CanDecrypt(encrypted)) {
          DVLOG(1) << "Implicit user provided passphrase accepted for "
                   << "decryption, overwriting default.";
          // Case 7. The pending keybag contains the current default. Go ahead
          // and update the cryptographer, letting the default change.
          cryptographer->DecryptPendingKeys(key_params);
          cryptographer->GetBootstrapToken(&bootstrap_token);
          success = true;
        } else {
          // Case 8. The pending keybag does not contain the current default
          // encryption key. We decrypt the pending keys here, and in
          // FinishSetPassphrase, re-encrypt everything with the current GAIA
          // passphrase instead of the passphrase just provided by the user.
          DVLOG(1) << "Implicit user provided passphrase accepted for "
                   << "decryption, restoring implicit internal passphrase "
                   << "as default.";
          std::string bootstrap_token_from_current_key;
          cryptographer->GetBootstrapToken(
              &bootstrap_token_from_current_key);
          cryptographer->DecryptPendingKeys(key_params);
          // Overwrite the default from the pending keys.
          cryptographer->AddKeyFromBootstrapToken(
              bootstrap_token_from_current_key);
          success = true;
        }
      } else {  // !temp_cryptographer.DecryptPendingKeys(..)
        DVLOG(1) << "Implicit user provided passphrase failed to decrypt.";
        success = false;
      }  // temp_cryptographer.DecryptPendingKeys(...)
    } else {  // cryptographer->is_initialized() == false
      if (cryptographer->DecryptPendingKeys(key_params)) {
        // This can happpen in two cases:
        // - First time sync on android, where we'll never have a
        //   !user_provided passphrase.
        // - This is a restart for a client that lost their bootstrap token.
        // In both cases, we should go ahead and initialize the cryptographer
        // and persist the new bootstrap token.
        //
        // Note: at this point, we cannot distinguish between cases 7 and 8
        // above. This user provided passphrase could be the current or the
        // old. But, as long as we persist the token, there's nothing more
        // we can do.
        cryptographer->GetBootstrapToken(&bootstrap_token);
        DVLOG(1) << "Implicit user provided passphrase accepted, initializing"
                 << " cryptographer.";
        success = true;
      } else {
        DVLOG(1) << "Implicit user provided passphrase failed to decrypt.";
        success = false;
      }
    }  // cryptographer->is_initialized()
  } else {  // nigori_has_explicit_passphrase == true
    // Case 9. Encryption was done with an explicit passphrase, and we decrypt
    // with the passphrase provided by the user.
    if (cryptographer->DecryptPendingKeys(key_params)) {
      DVLOG(1) << "Explicit passphrase accepted for decryption.";
      cryptographer->GetBootstrapToken(&bootstrap_token);
      success = true;
    } else {
      DVLOG(1) << "Explicit passphrase failed to decrypt.";
      success = false;
    }
  }  // nigori_has_explicit_passphrase

  DVLOG_IF(1, !success)
      << "Failure in SetDecryptionPassphrase; notifying and returning.";
  DVLOG_IF(1, success)
      << "Successfully set decryption passphrase; updating nigori and "
         "reencrypting.";

  FinishSetPassphrase(success, bootstrap_token, &trans, &node);
}

void SyncEncryptionHandlerImpl::EnableEncryptEverything() {
  DCHECK(thread_checker_.CalledOnValidThread());
  WriteTransaction trans(FROM_HERE, user_share_);
  DVLOG(1) << "Enabling encrypt everything.";
  if (encrypt_everything_)
    return;
  EnableEncryptEverythingImpl(trans.GetWrappedTrans());
  WriteEncryptionStateToNigori(&trans);
  if (UnlockVault(trans.GetWrappedTrans()).cryptographer.is_ready())
    ReEncryptEverything(&trans);
}

bool SyncEncryptionHandlerImpl::EncryptEverythingEnabled() const {
  DCHECK(thread_checker_.CalledOnValidThread());
  return encrypt_everything_;
}

PassphraseType SyncEncryptionHandlerImpl::GetPassphraseType() const {
  DCHECK(thread_checker_.CalledOnValidThread());
  return passphrase_type_;
}

// Note: this is called from within a syncable transaction, so we need to post
// tasks if we want to do any work that creates a new sync_api transaction.
void SyncEncryptionHandlerImpl::ApplyNigoriUpdate(
    const sync_pb::NigoriSpecifics& nigori,
    syncable::BaseTransaction* const trans) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(trans);
  if (!ApplyNigoriUpdateImpl(nigori, trans)) {
    base::MessageLoop::current()->PostTask(
        FROM_HERE,
        base::Bind(&SyncEncryptionHandlerImpl::RewriteNigori,
                   weak_ptr_factory_.GetWeakPtr()));
  }

  FOR_EACH_OBSERVER(
      SyncEncryptionHandler::Observer,
      observers_,
      OnCryptographerStateChanged(
          &UnlockVaultMutable(trans)->cryptographer));
}

void SyncEncryptionHandlerImpl::UpdateNigoriFromEncryptedTypes(
    sync_pb::NigoriSpecifics* nigori,
    syncable::BaseTransaction* const trans) const {
  DCHECK(thread_checker_.CalledOnValidThread());
  syncable::UpdateNigoriFromEncryptedTypes(UnlockVault(trans).encrypted_types,
                                           encrypt_everything_,
                                           nigori);
}

bool SyncEncryptionHandlerImpl::NeedKeystoreKey(
    syncable::BaseTransaction* const trans) const {
  DCHECK(thread_checker_.CalledOnValidThread());
  return keystore_key_.empty();
}

bool SyncEncryptionHandlerImpl::SetKeystoreKeys(
    const google::protobuf::RepeatedPtrField<google::protobuf::string>& keys,
    syncable::BaseTransaction* const trans) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (keys.size() == 0)
    return false;
  // The last key in the vector is the current keystore key. The others are kept
  // around for decryption only.
  const std::string& raw_keystore_key = keys.Get(keys.size() - 1);
  if (raw_keystore_key.empty())
    return false;

  // Note: in order to Pack the keys, they must all be base64 encoded (else
  // JSON serialization fails).
  base::Base64Encode(raw_keystore_key, &keystore_key_);

  // Go through and save the old keystore keys. We always persist all keystore
  // keys the server sends us.
  old_keystore_keys_.resize(keys.size() - 1);
  for (int i = 0; i < keys.size() - 1; ++i)
    base::Base64Encode(keys.Get(i), &old_keystore_keys_[i]);

  Cryptographer* cryptographer = &UnlockVaultMutable(trans)->cryptographer;

  // Update the bootstrap token. If this fails, we persist an empty string,
  // which will force us to download the keystore keys again on the next
  // restart.
  std::string keystore_bootstrap = PackKeystoreBootstrapToken(
      old_keystore_keys_,
      keystore_key_,
      cryptographer->encryptor());
  DCHECK_EQ(keystore_bootstrap.empty(), keystore_key_.empty());
  FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                    OnBootstrapTokenUpdated(keystore_bootstrap,
                                            KEYSTORE_BOOTSTRAP_TOKEN));
  DVLOG(1) << "Keystore bootstrap token updated.";

  // If this is a first time sync, we get the encryption keys before we process
  // the nigori node. Just return for now, ApplyNigoriUpdate will be invoked
  // once we have the nigori node.
  syncable::Entry entry(trans, syncable::GET_BY_SERVER_TAG, kNigoriTag);
  if (!entry.good())
    return true;

  const sync_pb::NigoriSpecifics& nigori =
      entry.GetSpecifics().nigori();
  if (cryptographer->has_pending_keys() &&
      IsNigoriMigratedToKeystore(nigori) &&
      !nigori.keystore_decryptor_token().blob().empty()) {
    // If the nigori is already migrated and we have pending keys, we might
    // be able to decrypt them using either the keystore decryptor token
    // or the existing keystore keys.
    DecryptPendingKeysWithKeystoreKey(keystore_key_,
                                      nigori.keystore_decryptor_token(),
                                      cryptographer);
  }

  // Note that triggering migration will have no effect if we're already
  // properly migrated with the newest keystore keys.
  if (ShouldTriggerMigration(nigori, *cryptographer)) {
    base::MessageLoop::current()->PostTask(
        FROM_HERE,
        base::Bind(&SyncEncryptionHandlerImpl::RewriteNigori,
                   weak_ptr_factory_.GetWeakPtr()));
  }

  return true;
}

ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypes(
    syncable::BaseTransaction* const trans) const {
  return UnlockVault(trans).encrypted_types;
}

Cryptographer* SyncEncryptionHandlerImpl::GetCryptographerUnsafe() {
  DCHECK(thread_checker_.CalledOnValidThread());
  return &vault_unsafe_.cryptographer;
}

ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypesUnsafe() {
  DCHECK(thread_checker_.CalledOnValidThread());
  return vault_unsafe_.encrypted_types;
}

bool SyncEncryptionHandlerImpl::MigratedToKeystore() {
  DCHECK(thread_checker_.CalledOnValidThread());
  ReadTransaction trans(FROM_HERE, user_share_);
  ReadNode nigori_node(&trans);
  if (nigori_node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK)
    return false;
  return IsNigoriMigratedToKeystore(nigori_node.GetNigoriSpecifics());
}

base::Time SyncEncryptionHandlerImpl::migration_time() const {
  return migration_time_;
}

base::Time SyncEncryptionHandlerImpl::custom_passphrase_time() const {
  return custom_passphrase_time_;
}

// This function iterates over all encrypted types.  There are many scenarios in
// which data for some or all types is not currently available.  In that case,
// the lookup of the root node will fail and we will skip encryption for that
// type.
void SyncEncryptionHandlerImpl::ReEncryptEverything(
    WriteTransaction* trans) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(UnlockVault(trans->GetWrappedTrans()).cryptographer.is_ready());
  for (ModelTypeSet::Iterator iter =
           UnlockVault(trans->GetWrappedTrans()).encrypted_types.First();
       iter.Good(); iter.Inc()) {
    if (iter.Get() == PASSWORDS || IsControlType(iter.Get()))
      continue; // These types handle encryption differently.

    ReadNode type_root(trans);
    std::string tag = ModelTypeToRootTag(iter.Get());
    if (type_root.InitByTagLookup(tag) != BaseNode::INIT_OK)
      continue; // Don't try to reencrypt if the type's data is unavailable.

    // Iterate through all children of this datatype.
    std::queue<int64> to_visit;
    int64 child_id = type_root.GetFirstChildId();
    to_visit.push(child_id);
    while (!to_visit.empty()) {
      child_id = to_visit.front();
      to_visit.pop();
      if (child_id == kInvalidId)
        continue;

      WriteNode child(trans);
      if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK)
        continue;  // Possible for locally deleted items.
      if (child.GetIsFolder()) {
        to_visit.push(child.GetFirstChildId());
      }
      if (child.GetEntry()->GetUniqueServerTag().empty()) {
      // Rewrite the specifics of the node with encrypted data if necessary
      // (only rewrite the non-unique folders).
        child.ResetFromSpecifics();
      }
      to_visit.push(child.GetSuccessorId());
    }
  }

  // Passwords are encrypted with their own legacy scheme.  Passwords are always
  // encrypted so we don't need to check GetEncryptedTypes() here.
  ReadNode passwords_root(trans);
  std::string passwords_tag = ModelTypeToRootTag(PASSWORDS);
  if (passwords_root.InitByTagLookup(passwords_tag) ==
          BaseNode::INIT_OK) {
    int64 child_id = passwords_root.GetFirstChildId();
    while (child_id != kInvalidId) {
      WriteNode child(trans);
      if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK) {
        NOTREACHED();
        return;
      }
      child.SetPasswordSpecifics(child.GetPasswordSpecifics());
      child_id = child.GetSuccessorId();
    }
  }

  DVLOG(1) << "Re-encrypt everything complete.";

  // NOTE: We notify from within a transaction.
  FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                    OnEncryptionComplete());
}

bool SyncEncryptionHandlerImpl::ApplyNigoriUpdateImpl(
    const sync_pb::NigoriSpecifics& nigori,
    syncable::BaseTransaction* const trans) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DVLOG(1) << "Applying nigori node update.";
  bool nigori_types_need_update = !UpdateEncryptedTypesFromNigori(nigori,
                                                                  trans);

  if (nigori.custom_passphrase_time() != 0) {
    custom_passphrase_time_ =
        ProtoTimeToTime(nigori.custom_passphrase_time());
  }
  bool is_nigori_migrated = IsNigoriMigratedToKeystore(nigori);
  if (is_nigori_migrated) {
    DCHECK(nigori.has_keystore_migration_time());
    migration_time_ = ProtoTimeToTime(nigori.keystore_migration_time());
    PassphraseType nigori_passphrase_type =
        ProtoPassphraseTypeToEnum(nigori.passphrase_type());

    // Only update the local passphrase state if it's a valid transition:
    // - implicit -> keystore
    // - implicit -> frozen implicit
    // - implicit -> custom
    // - keystore -> custom
    // Note: frozen implicit -> custom is not technically a valid transition,
    // but we let it through here as well in case future versions do add support
    // for this transition.
    if (passphrase_type_ != nigori_passphrase_type &&
        nigori_passphrase_type != IMPLICIT_PASSPHRASE &&
        (passphrase_type_ == IMPLICIT_PASSPHRASE ||
         nigori_passphrase_type == CUSTOM_PASSPHRASE)) {
      DVLOG(1) << "Changing passphrase state from "
               << PassphraseTypeToString(passphrase_type_)
               << " to "
               << PassphraseTypeToString(nigori_passphrase_type);
      passphrase_type_ = nigori_passphrase_type;
      FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                            OnPassphraseTypeChanged(
                                passphrase_type_,
                                GetExplicitPassphraseTime()));
    }
    if (passphrase_type_ == KEYSTORE_PASSPHRASE && encrypt_everything_) {
      // This is the case where another client that didn't support keystore
      // encryption attempted to enable full encryption. We detect it
      // and switch the passphrase type to frozen implicit passphrase instead
      // due to full encryption not being compatible with keystore passphrase.
      // Because the local passphrase type will not match the nigori passphrase
      // type, we will trigger a rewrite and subsequently a re-migration.
      DVLOG(1) << "Changing passphrase state to FROZEN_IMPLICIT_PASSPHRASE "
               << "due to full encryption.";
      passphrase_type_ = FROZEN_IMPLICIT_PASSPHRASE;
      FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                            OnPassphraseTypeChanged(
                                passphrase_type_,
                                GetExplicitPassphraseTime()));
    }
  } else {
    // It's possible that while we're waiting for migration a client that does
    // not have keystore encryption enabled switches to a custom passphrase.
    if (nigori.keybag_is_frozen() &&
        passphrase_type_ != CUSTOM_PASSPHRASE) {
      passphrase_type_ = CUSTOM_PASSPHRASE;
      FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                            OnPassphraseTypeChanged(
                                passphrase_type_,
                                GetExplicitPassphraseTime()));
    }
  }

  Cryptographer* cryptographer = &UnlockVaultMutable(trans)->cryptographer;
  bool nigori_needs_new_keys = false;
  if (!nigori.encryption_keybag().blob().empty()) {
    // We only update the default key if this was a new explicit passphrase.
    // Else, since it was decryptable, it must not have been a new key.
    bool need_new_default_key = false;
    if (is_nigori_migrated) {
      need_new_default_key = IsExplicitPassphrase(
          ProtoPassphraseTypeToEnum(nigori.passphrase_type()));
    } else {
      need_new_default_key = nigori.keybag_is_frozen();
    }
    if (!AttemptToInstallKeybag(nigori.encryption_keybag(),
                                need_new_default_key,
                                cryptographer)) {
      // Check to see if we can decrypt the keybag using the keystore decryptor
      // token.
      cryptographer->SetPendingKeys(nigori.encryption_keybag());
      if (!nigori.keystore_decryptor_token().blob().empty() &&
          !keystore_key_.empty()) {
        if (DecryptPendingKeysWithKeystoreKey(keystore_key_,
                                              nigori.keystore_decryptor_token(),
                                              cryptographer)) {
          nigori_needs_new_keys =
              cryptographer->KeybagIsStale(nigori.encryption_keybag());
        } else {
          LOG(ERROR) << "Failed to decrypt pending keys using keystore "
                     << "bootstrap key.";
        }
      }
    } else {
      // Keybag was installed. We write back our local keybag into the nigori
      // node if the nigori node's keybag either contains less keys or
      // has a different default key.
      nigori_needs_new_keys =
          cryptographer->KeybagIsStale(nigori.encryption_keybag());
    }
  } else {
    // The nigori node has an empty encryption keybag. Attempt to write our
    // local encryption keys into it.
    LOG(WARNING) << "Nigori had empty encryption keybag.";
    nigori_needs_new_keys = true;
  }

  // If we've completed a sync cycle and the cryptographer isn't ready
  // yet or has pending keys, prompt the user for a passphrase.
  if (cryptographer->has_pending_keys()) {
    DVLOG(1) << "OnPassphraseRequired Sent";
    sync_pb::EncryptedData pending_keys = cryptographer->GetPendingKeys();
    FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                      OnPassphraseRequired(REASON_DECRYPTION,
                                           pending_keys));
  } else if (!cryptographer->is_ready()) {
    DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not "
             << "ready";
    FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                      OnPassphraseRequired(REASON_ENCRYPTION,
                                           sync_pb::EncryptedData()));
  }

  // Check if the current local encryption state is stricter/newer than the
  // nigori state. If so, we need to overwrite the nigori node with the local
  // state.
  bool passphrase_type_matches = true;
  if (!is_nigori_migrated) {
    DCHECK(passphrase_type_ == CUSTOM_PASSPHRASE ||
           passphrase_type_ == IMPLICIT_PASSPHRASE);
    passphrase_type_matches =
        nigori.keybag_is_frozen() == IsExplicitPassphrase(passphrase_type_);
  } else {
    passphrase_type_matches =
        (ProtoPassphraseTypeToEnum(nigori.passphrase_type()) ==
             passphrase_type_);
  }
  if (!passphrase_type_matches ||
      nigori.encrypt_everything() != encrypt_everything_ ||
      nigori_types_need_update ||
      nigori_needs_new_keys) {
    DVLOG(1) << "Triggering nigori rewrite.";
    return false;
  }
  return true;
}

void SyncEncryptionHandlerImpl::RewriteNigori() {
  DVLOG(1) << "Writing local encryption state into nigori.";
  DCHECK(thread_checker_.CalledOnValidThread());
  WriteTransaction trans(FROM_HERE, user_share_);
  WriteEncryptionStateToNigori(&trans);
}

void SyncEncryptionHandlerImpl::WriteEncryptionStateToNigori(
    WriteTransaction* trans) {
  DCHECK(thread_checker_.CalledOnValidThread());
  WriteNode nigori_node(trans);
  // This can happen in tests that don't have nigori nodes.
  if (nigori_node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK)
    return;

  sync_pb::NigoriSpecifics nigori = nigori_node.GetNigoriSpecifics();
  const Cryptographer& cryptographer =
      UnlockVault(trans->GetWrappedTrans()).cryptographer;

  // Will not do anything if we shouldn't or can't migrate. Otherwise
  // migrates, writing the full encryption state as it does.
  if (!AttemptToMigrateNigoriToKeystore(trans, &nigori_node)) {
    if (cryptographer.is_ready() &&
        nigori_overwrite_count_ < kNigoriOverwriteLimit) {
      // Does not modify the encrypted blob if the unencrypted data already
      // matches what is about to be written.
      sync_pb::EncryptedData original_keys = nigori.encryption_keybag();
      if (!cryptographer.GetKeys(nigori.mutable_encryption_keybag()))
        NOTREACHED();

      if (nigori.encryption_keybag().SerializeAsString() !=
          original_keys.SerializeAsString()) {
        // We've updated the nigori node's encryption keys. In order to prevent
        // a possible looping of two clients constantly overwriting each other,
        // we limit the absolute number of overwrites per client instantiation.
        nigori_overwrite_count_++;
        UMA_HISTOGRAM_COUNTS("Sync.AutoNigoriOverwrites",
                             nigori_overwrite_count_);
      }

      // Note: we don't try to set keybag_is_frozen here since if that
      // is lost the user can always set it again (and we don't want to clobber
      // any migration state). The main goal at this point is to preserve
      // the encryption keys so all data remains decryptable.
    }
    syncable::UpdateNigoriFromEncryptedTypes(
        UnlockVault(trans->GetWrappedTrans()).encrypted_types,
        encrypt_everything_,
        &nigori);
    if (!custom_passphrase_time_.is_null()) {
      nigori.set_custom_passphrase_time(
          TimeToProtoTime(custom_passphrase_time_));
    }

    // If nothing has changed, this is a no-op.
    nigori_node.SetNigoriSpecifics(nigori);
  }
}

bool SyncEncryptionHandlerImpl::UpdateEncryptedTypesFromNigori(
    const sync_pb::NigoriSpecifics& nigori,
    syncable::BaseTransaction* const trans) {
  DCHECK(thread_checker_.CalledOnValidThread());
  ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types;
  if (nigori.encrypt_everything()) {
    EnableEncryptEverythingImpl(trans);
    DCHECK(encrypted_types->Equals(EncryptableUserTypes()));
    return true;
  } else if (encrypt_everything_) {
    DCHECK(encrypted_types->Equals(EncryptableUserTypes()));
    return false;
  }

  ModelTypeSet nigori_encrypted_types;
  nigori_encrypted_types = syncable::GetEncryptedTypesFromNigori(nigori);
  nigori_encrypted_types.PutAll(SensitiveTypes());

  // If anything more than the sensitive types were encrypted, and
  // encrypt_everything is not explicitly set to false, we assume it means
  // a client intended to enable encrypt everything.
  if (!nigori.has_encrypt_everything() &&
      !Difference(nigori_encrypted_types, SensitiveTypes()).Empty()) {
    if (!encrypt_everything_) {
      encrypt_everything_ = true;
      *encrypted_types = EncryptableUserTypes();
      FOR_EACH_OBSERVER(
          Observer, observers_,
          OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_));
    }
    DCHECK(encrypted_types->Equals(EncryptableUserTypes()));
    return false;
  }

  MergeEncryptedTypes(nigori_encrypted_types, trans);
  return encrypted_types->Equals(nigori_encrypted_types);
}

void SyncEncryptionHandlerImpl::SetCustomPassphrase(
    const std::string& passphrase,
    WriteTransaction* trans,
    WriteNode* nigori_node) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(IsNigoriMigratedToKeystore(nigori_node->GetNigoriSpecifics()));
  KeyParams key_params = {"localhost", "dummy", passphrase};

  if (passphrase_type_ != KEYSTORE_PASSPHRASE) {
    DVLOG(1) << "Failing to set a custom passphrase because one has already "
             << "been set.";
    FinishSetPassphrase(false, std::string(), trans, nigori_node);
    return;
  }

  Cryptographer* cryptographer =
      &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer;
  if (cryptographer->has_pending_keys()) {
    // This theoretically shouldn't happen, because the only way to have pending
    // keys after migrating to keystore support is if a custom passphrase was
    // set, which should update passpshrase_state_ and should be caught by the
    // if statement above. For the sake of safety though, we check for it in
    // case a client is misbehaving.
    LOG(ERROR) << "Failing to set custom passphrase because of pending keys.";
    FinishSetPassphrase(false, std::string(), trans, nigori_node);
    return;
  }

  std::string bootstrap_token;
  if (cryptographer->AddKey(key_params)) {
    DVLOG(1) << "Setting custom passphrase.";
    cryptographer->GetBootstrapToken(&bootstrap_token);
    passphrase_type_ = CUSTOM_PASSPHRASE;
    custom_passphrase_time_ = base::Time::Now();
    FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                            OnPassphraseTypeChanged(
                                passphrase_type_,
                                GetExplicitPassphraseTime()));
  } else {
    NOTREACHED() << "Failed to add key to cryptographer.";
    return;
  }
  FinishSetPassphrase(true, bootstrap_token, trans, nigori_node);
}

void SyncEncryptionHandlerImpl::DecryptPendingKeysWithExplicitPassphrase(
    const std::string& passphrase,
    WriteTransaction* trans,
    WriteNode* nigori_node) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(IsExplicitPassphrase(passphrase_type_));
  KeyParams key_params = {"localhost", "dummy", passphrase};

  Cryptographer* cryptographer =
      &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer;
  if (!cryptographer->has_pending_keys()) {
    // Note that this *can* happen in a rare situation where data is
    // re-encrypted on another client while a SetDecryptionPassphrase() call is
    // in-flight on this client. It is rare enough that we choose to do nothing.
    NOTREACHED() << "Attempt to set decryption passphrase failed because there "
                 << "were no pending keys.";
    return;
  }

  DCHECK(IsExplicitPassphrase(passphrase_type_));
  bool success = false;
  std::string bootstrap_token;
  if (cryptographer->DecryptPendingKeys(key_params)) {
    DVLOG(1) << "Explicit passphrase accepted for decryption.";
    cryptographer->GetBootstrapToken(&bootstrap_token);
    success = true;
  } else {
    DVLOG(1) << "Explicit passphrase failed to decrypt.";
    success = false;
  }
  if (success && !keystore_key_.empty()) {
    // Should already be part of the encryption keybag, but we add it just
    // in case.
    KeyParams key_params = {"localhost", "dummy", keystore_key_};
    cryptographer->AddNonDefaultKey(key_params);
  }
  FinishSetPassphrase(success, bootstrap_token, trans, nigori_node);
}

void SyncEncryptionHandlerImpl::FinishSetPassphrase(
    bool success,
    const std::string& bootstrap_token,
    WriteTransaction* trans,
    WriteNode* nigori_node) {
  DCHECK(thread_checker_.CalledOnValidThread());
  FOR_EACH_OBSERVER(
      SyncEncryptionHandler::Observer,
      observers_,
      OnCryptographerStateChanged(
          &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer));

  // It's possible we need to change the bootstrap token even if we failed to
  // set the passphrase (for example if we need to preserve the new GAIA
  // passphrase).
  if (!bootstrap_token.empty()) {
    DVLOG(1) << "Passphrase bootstrap token updated.";
    FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                      OnBootstrapTokenUpdated(bootstrap_token,
                                              PASSPHRASE_BOOTSTRAP_TOKEN));
  }

  const Cryptographer& cryptographer =
      UnlockVault(trans->GetWrappedTrans()).cryptographer;
  if (!success) {
    if (cryptographer.is_ready()) {
      LOG(ERROR) << "Attempt to change passphrase failed while cryptographer "
                 << "was ready.";
    } else if (cryptographer.has_pending_keys()) {
      FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                        OnPassphraseRequired(REASON_DECRYPTION,
                                             cryptographer.GetPendingKeys()));
    } else {
      FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                        OnPassphraseRequired(REASON_ENCRYPTION,
                                             sync_pb::EncryptedData()));
    }
    return;
  }
  DCHECK(success);
  DCHECK(cryptographer.is_ready());

  // Will do nothing if we're already properly migrated or unable to migrate
  // (in otherwords, if ShouldTriggerMigration is false).
  // Otherwise will update the nigori node with the current migrated state,
  // writing all encryption state as it does.
  if (!AttemptToMigrateNigoriToKeystore(trans, nigori_node)) {
    sync_pb::NigoriSpecifics nigori(nigori_node->GetNigoriSpecifics());
    // Does not modify nigori.encryption_keybag() if the original decrypted
    // data was the same.
    if (!cryptographer.GetKeys(nigori.mutable_encryption_keybag()))
      NOTREACHED();
    if (IsNigoriMigratedToKeystore(nigori)) {
      DCHECK(keystore_key_.empty() || IsExplicitPassphrase(passphrase_type_));
      DVLOG(1) << "Leaving nigori migration state untouched after setting"
               << " passphrase.";
    } else {
      nigori.set_keybag_is_frozen(
          IsExplicitPassphrase(passphrase_type_));
    }
    // If we set a new custom passphrase, store the timestamp.
    if (!custom_passphrase_time_.is_null()) {
      nigori.set_custom_passphrase_time(
          TimeToProtoTime(custom_passphrase_time_));
    }
    nigori_node->SetNigoriSpecifics(nigori);
  }

  // Must do this after OnPassphraseTypeChanged, in order to ensure the PSS
  // checks the passphrase state after it has been set.
  FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                    OnPassphraseAccepted());

  // Does nothing if everything is already encrypted.
  // TODO(zea): If we just migrated and enabled encryption, this will be
  // redundant. Figure out a way to not do this unnecessarily.
  ReEncryptEverything(trans);
}

void SyncEncryptionHandlerImpl::MergeEncryptedTypes(
    ModelTypeSet new_encrypted_types,
    syncable::BaseTransaction* const trans) {
  DCHECK(thread_checker_.CalledOnValidThread());

  // Only UserTypes may be encrypted.
  DCHECK(EncryptableUserTypes().HasAll(new_encrypted_types));

  ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types;
  if (!encrypted_types->HasAll(new_encrypted_types)) {
    *encrypted_types = new_encrypted_types;
    FOR_EACH_OBSERVER(
        Observer, observers_,
        OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_));
  }
}

SyncEncryptionHandlerImpl::Vault* SyncEncryptionHandlerImpl::UnlockVaultMutable(
    syncable::BaseTransaction* const trans) {
  DCHECK_EQ(user_share_->directory.get(), trans->directory());
  return &vault_unsafe_;
}

const SyncEncryptionHandlerImpl::Vault& SyncEncryptionHandlerImpl::UnlockVault(
    syncable::BaseTransaction* const trans) const {
  DCHECK_EQ(user_share_->directory.get(), trans->directory());
  return vault_unsafe_;
}

bool SyncEncryptionHandlerImpl::ShouldTriggerMigration(
    const sync_pb::NigoriSpecifics& nigori,
    const Cryptographer& cryptographer) const {
  DCHECK(thread_checker_.CalledOnValidThread());
  // Don't migrate if there are pending encryption keys (because data
  // encrypted with the pending keys will not be decryptable).
  if (cryptographer.has_pending_keys())
    return false;
  if (IsNigoriMigratedToKeystore(nigori)) {
    // If the nigori is already migrated but does not reflect the explicit
    // passphrase state, remigrate. Similarly, if the nigori has an explicit
    // passphrase but does not have full encryption, or the nigori has an
    // implicit passphrase but does have full encryption, re-migrate.
    // Note that this is to defend against other clients without keystore
    // encryption enabled transitioning to states that are no longer valid.
    if (passphrase_type_ != KEYSTORE_PASSPHRASE &&
        nigori.passphrase_type() ==
            sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE) {
      return true;
    } else if (IsExplicitPassphrase(passphrase_type_) &&
               !encrypt_everything_) {
      return true;
    } else if (passphrase_type_ == KEYSTORE_PASSPHRASE &&
               encrypt_everything_) {
      return true;
    } else if (
        cryptographer.is_ready() &&
        !cryptographer.CanDecryptUsingDefaultKey(nigori.encryption_keybag())) {
      // We need to overwrite the keybag. This might involve overwriting the
      // keystore decryptor too.
      return true;
    } else if (old_keystore_keys_.size() > 0 && !keystore_key_.empty()) {
      // Check to see if a server key rotation has happened, but the nigori
      // node's keys haven't been rotated yet, and hence we should re-migrate.
      // Note that once a key rotation has been performed, we no longer
      // preserve backwards compatibility, and the keybag will therefore be
      // encrypted with the current keystore key.
      Cryptographer temp_cryptographer(cryptographer.encryptor());
      KeyParams keystore_params = {"localhost", "dummy", keystore_key_};
      temp_cryptographer.AddKey(keystore_params);
      if (!temp_cryptographer.CanDecryptUsingDefaultKey(
              nigori.encryption_keybag())) {
        return true;
      }
    }
    return false;
  } else if (keystore_key_.empty()) {
    // If we haven't already migrated, we don't want to do anything unless
    // a keystore key is available (so that those clients without keystore
    // encryption enabled aren't forced into new states, e.g. frozen implicit
    // passphrase).
    return false;
  }
  return true;
}

bool SyncEncryptionHandlerImpl::AttemptToMigrateNigoriToKeystore(
    WriteTransaction* trans,
    WriteNode* nigori_node) {
  DCHECK(thread_checker_.CalledOnValidThread());
  const sync_pb::NigoriSpecifics& old_nigori =
      nigori_node->GetNigoriSpecifics();
  Cryptographer* cryptographer =
      &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer;

  if (!ShouldTriggerMigration(old_nigori, *cryptographer))
    return false;

  DVLOG(1) << "Starting nigori migration to keystore support.";
  sync_pb::NigoriSpecifics migrated_nigori(old_nigori);

  PassphraseType new_passphrase_type = passphrase_type_;
  bool new_encrypt_everything = encrypt_everything_;
  if (encrypt_everything_ && !IsExplicitPassphrase(passphrase_type_)) {
    DVLOG(1) << "Switching to frozen implicit passphrase due to already having "
             << "full encryption.";
    new_passphrase_type = FROZEN_IMPLICIT_PASSPHRASE;
    migrated_nigori.clear_keystore_decryptor_token();
  } else if (IsExplicitPassphrase(passphrase_type_)) {
    DVLOG_IF(1, !encrypt_everything_) << "Enabling encrypt everything due to "
                                      << "explicit passphrase";
    new_encrypt_everything = true;
    migrated_nigori.clear_keystore_decryptor_token();
  } else {
    DCHECK(!encrypt_everything_);
    new_passphrase_type = KEYSTORE_PASSPHRASE;
    DVLOG(1) << "Switching to keystore passphrase state.";
  }
  migrated_nigori.set_encrypt_everything(new_encrypt_everything);
  migrated_nigori.set_passphrase_type(
      EnumPassphraseTypeToProto(new_passphrase_type));
  migrated_nigori.set_keybag_is_frozen(true);

  if (!keystore_key_.empty()) {
    KeyParams key_params = {"localhost", "dummy", keystore_key_};
    if ((old_keystore_keys_.size() > 0 &&
         new_passphrase_type == KEYSTORE_PASSPHRASE) ||
        !cryptographer->is_initialized()) {
      // Either at least one key rotation has been performed, so we no longer
      // care about backwards compatibility, or we're generating keystore-based
      // encryption keys without knowing the GAIA password (and therefore the
      // cryptographer is not initialized), so we can't support backwards
      // compatibility. Ensure the keystore key is the default key.
      DVLOG(1) << "Migrating keybag to keystore key.";
      bool cryptographer_was_ready = cryptographer->is_ready();
      if (!cryptographer->AddKey(key_params)) {
        LOG(ERROR) << "Failed to add keystore key as default key";
        UMA_HISTOGRAM_ENUMERATION("Sync.AttemptNigoriMigration",
                                  FAILED_TO_SET_DEFAULT_KEYSTORE,
                                  MIGRATION_RESULT_SIZE);
        return false;
      }
      if (!cryptographer_was_ready && cryptographer->is_ready()) {
        FOR_EACH_OBSERVER(
            SyncEncryptionHandler::Observer,
            observers_,
            OnPassphraseAccepted());
      }
    } else {
      // We're in backwards compatible mode -- either the account has an
      // explicit passphrase, or we want to preserve the current GAIA-based key
      // as the default because we can (there have been no key rotations since
      // the migration).
      DVLOG(1) << "Migrating keybag while preserving old key";
      if (!cryptographer->AddNonDefaultKey(key_params)) {
        LOG(ERROR) << "Failed to add keystore key as non-default key.";
        UMA_HISTOGRAM_ENUMERATION("Sync.AttemptNigoriMigration",
                                  FAILED_TO_SET_NONDEFAULT_KEYSTORE,
                                  MIGRATION_RESULT_SIZE);
        return false;
      }
    }
  }
  if (!old_keystore_keys_.empty()) {
    // Go through and add all the old keystore keys as non default keys, so
    // they'll be preserved in the encryption_keybag when we next write the
    // nigori node.
    for (std::vector<std::string>::const_iterator iter =
             old_keystore_keys_.begin(); iter != old_keystore_keys_.end();
         ++iter) {
      KeyParams key_params = {"localhost", "dummy", *iter};
      cryptographer->AddNonDefaultKey(key_params);
    }
  }
  if (new_passphrase_type == KEYSTORE_PASSPHRASE &&
      !GetKeystoreDecryptor(
          *cryptographer,
          keystore_key_,
          migrated_nigori.mutable_keystore_decryptor_token())) {
    LOG(ERROR) << "Failed to extract keystore decryptor token.";
    UMA_HISTOGRAM_ENUMERATION("Sync.AttemptNigoriMigration",
                              FAILED_TO_EXTRACT_DECRYPTOR,
                              MIGRATION_RESULT_SIZE);
    return false;
  }
  if (!cryptographer->GetKeys(migrated_nigori.mutable_encryption_keybag())) {
    LOG(ERROR) << "Failed to extract encryption keybag.";
    UMA_HISTOGRAM_ENUMERATION("Sync.AttemptNigoriMigration",
                              FAILED_TO_EXTRACT_KEYBAG,
                              MIGRATION_RESULT_SIZE);
    return false;
  }

  if (migration_time_.is_null())
    migration_time_ = base::Time::Now();
  migrated_nigori.set_keystore_migration_time(TimeToProtoTime(migration_time_));

  if (!custom_passphrase_time_.is_null()) {
    migrated_nigori.set_custom_passphrase_time(
        TimeToProtoTime(custom_passphrase_time_));
  }

  FOR_EACH_OBSERVER(
      SyncEncryptionHandler::Observer,
      observers_,
      OnCryptographerStateChanged(cryptographer));
  if (passphrase_type_ != new_passphrase_type) {
    passphrase_type_ = new_passphrase_type;
    FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
                            OnPassphraseTypeChanged(
                                passphrase_type_,
                                GetExplicitPassphraseTime()));
  }

  if (new_encrypt_everything && !encrypt_everything_) {
    EnableEncryptEverythingImpl(trans->GetWrappedTrans());
    ReEncryptEverything(trans);
  } else if (!cryptographer->CanDecryptUsingDefaultKey(
                 old_nigori.encryption_keybag())) {
    DVLOG(1) << "Rencrypting everything due to key rotation.";
    ReEncryptEverything(trans);
  }

  DVLOG(1) << "Completing nigori migration to keystore support.";
  nigori_node->SetNigoriSpecifics(migrated_nigori);

  switch (new_passphrase_type) {
    case KEYSTORE_PASSPHRASE:
      if (old_keystore_keys_.size() > 0) {
        UMA_HISTOGRAM_ENUMERATION("Sync.AttemptNigoriMigration",
                                  MIGRATION_SUCCESS_KEYSTORE_NONDEFAULT,
                                  MIGRATION_RESULT_SIZE);
      } else {
        UMA_HISTOGRAM_ENUMERATION("Sync.AttemptNigoriMigration",
                                  MIGRATION_SUCCESS_KEYSTORE_DEFAULT,
                                  MIGRATION_RESULT_SIZE);
      }
      break;
    case FROZEN_IMPLICIT_PASSPHRASE:
      UMA_HISTOGRAM_ENUMERATION("Sync.AttemptNigoriMigration",
                                MIGRATION_SUCCESS_FROZEN_IMPLICIT,
                                MIGRATION_RESULT_SIZE);
      break;
    case CUSTOM_PASSPHRASE:
      UMA_HISTOGRAM_ENUMERATION("Sync.AttemptNigoriMigration",
                                MIGRATION_SUCCESS_CUSTOM,
                                MIGRATION_RESULT_SIZE);
      break;
    default:
      NOTREACHED();
      break;
  }
  return true;
}

bool SyncEncryptionHandlerImpl::GetKeystoreDecryptor(
    const Cryptographer& cryptographer,
    const std::string& keystore_key,
    sync_pb::EncryptedData* encrypted_blob) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(!keystore_key.empty());
  DCHECK(cryptographer.is_ready());
  std::string serialized_nigori;
  serialized_nigori = cryptographer.GetDefaultNigoriKey();
  if (serialized_nigori.empty()) {
    LOG(ERROR) << "Failed to get cryptographer bootstrap token.";
    return false;
  }
  Cryptographer temp_cryptographer(cryptographer.encryptor());
  KeyParams key_params = {"localhost", "dummy", keystore_key};
  if (!temp_cryptographer.AddKey(key_params))
    return false;
  if (!temp_cryptographer.EncryptString(serialized_nigori, encrypted_blob))
    return false;
  return true;
}

bool SyncEncryptionHandlerImpl::AttemptToInstallKeybag(
    const sync_pb::EncryptedData& keybag,
    bool update_default,
    Cryptographer* cryptographer) {
  if (!cryptographer->CanDecrypt(keybag))
    return false;
  cryptographer->InstallKeys(keybag);
  if (update_default)
    cryptographer->SetDefaultKey(keybag.key_name());
  return true;
}

void SyncEncryptionHandlerImpl::EnableEncryptEverythingImpl(
    syncable::BaseTransaction* const trans) {
  ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types;
  if (encrypt_everything_) {
    DCHECK(encrypted_types->Equals(EncryptableUserTypes()));
    return;
  }
  encrypt_everything_ = true;
  *encrypted_types = EncryptableUserTypes();
  FOR_EACH_OBSERVER(
      Observer, observers_,
      OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_));
}

bool SyncEncryptionHandlerImpl::DecryptPendingKeysWithKeystoreKey(
    const std::string& keystore_key,
    const sync_pb::EncryptedData& keystore_decryptor_token,
    Cryptographer* cryptographer) {
  DCHECK(cryptographer->has_pending_keys());
  if (keystore_decryptor_token.blob().empty())
    return false;
  Cryptographer temp_cryptographer(cryptographer->encryptor());

  // First, go through and all all the old keystore keys to the temporary
  // cryptographer.
  for (size_t i = 0; i < old_keystore_keys_.size(); ++i) {
    KeyParams old_key_params = {"localhost", "dummy", old_keystore_keys_[i]};
    temp_cryptographer.AddKey(old_key_params);
  }

  // Then add the current keystore key as the default key and see if we can
  // decrypt.
  KeyParams keystore_params = {"localhost", "dummy", keystore_key_};
  if (temp_cryptographer.AddKey(keystore_params) &&
      temp_cryptographer.CanDecrypt(keystore_decryptor_token)) {
    // Someone else migrated the nigori for us! How generous! Go ahead and
    // install both the keystore key and the new default encryption key
    // (i.e. the one provided by the keystore decryptor token) into the
    // cryptographer.
    // The keystore decryptor token is a keystore key encrypted blob containing
    // the current serialized default encryption key (and as such should be
    // able to decrypt the nigori node's encryption keybag).
    // Note: it's possible a key rotation has happened since the migration, and
    // we're decrypting using an old keystore key. In that case we need to
    // ensure we re-encrypt using the newest key.
    DVLOG(1) << "Attempting to decrypt pending keys using "
             << "keystore decryptor token.";
    std::string serialized_nigori =
        temp_cryptographer.DecryptToString(keystore_decryptor_token);

    // This will decrypt the pending keys and add them if possible. The key
    // within |serialized_nigori| will be the default after.
    cryptographer->ImportNigoriKey(serialized_nigori);

    if (!temp_cryptographer.CanDecryptUsingDefaultKey(
            keystore_decryptor_token)) {
      // The keystore decryptor token was derived from an old keystore key.
      // A key rotation is necessary, so set the current keystore key as the
      // default key (which will trigger a re-migration).
      DVLOG(1) << "Pending keys based on old keystore key. Setting newest "
               << "keystore key as default.";
      cryptographer->AddKey(keystore_params);
    } else {
      // Theoretically the encryption keybag should already contain the keystore
      // key. We explicitly add it as a safety measure.
      DVLOG(1) << "Pending keys based on newest keystore key.";
      cryptographer->AddNonDefaultKey(keystore_params);
    }
    if (cryptographer->is_ready()) {
      std::string bootstrap_token;
      cryptographer->GetBootstrapToken(&bootstrap_token);
      DVLOG(1) << "Keystore decryptor token decrypted pending keys.";
      FOR_EACH_OBSERVER(
          SyncEncryptionHandler::Observer,
          observers_,
          OnPassphraseAccepted());
      FOR_EACH_OBSERVER(
          SyncEncryptionHandler::Observer,
          observers_,
          OnBootstrapTokenUpdated(bootstrap_token,
                                  PASSPHRASE_BOOTSTRAP_TOKEN));
      FOR_EACH_OBSERVER(
          SyncEncryptionHandler::Observer,
          observers_,
          OnCryptographerStateChanged(cryptographer));
      return true;
    }
  }
  return false;
}

base::Time SyncEncryptionHandlerImpl::GetExplicitPassphraseTime() const {
  if (passphrase_type_ == FROZEN_IMPLICIT_PASSPHRASE)
    return migration_time();
  else if (passphrase_type_ == CUSTOM_PASSPHRASE)
    return custom_passphrase_time();
  return base::Time();
}

}  // namespace browser_sync