log_op ? rgw::sal::FLAG_LOG_OP : 0);
 }
 
+int fixup_manifest_to_parts_len(const DoutPrefixProvider *dpp, std::map<std::string, ceph::buffer::list> &src_attrs) {
+  auto iter = src_attrs.find(RGW_ATTR_MANIFEST);
+  if (iter == src_attrs.end()) {
+    return 0;
+  }
+  bufferlist &manifest_bl { iter->second };
+//        manifest_bl = std::copy(iter->second);
+//        src_attrs.erase(iter);
+
+  // if the source object was encrypted, preserve the part lengths from
+  // the original object's manifest in RGW_ATTR_CRYPT_PARTS. if the object
+  // already replicated and has the RGW_ATTR_CRYPT_PARTS attr, preserve it
+  if (src_attrs.count(RGW_ATTR_CRYPT_MODE) &&
+      !src_attrs.count(RGW_ATTR_CRYPT_PARTS)) {
+    std::vector<size_t> parts_len;
+    int r = RGWGetObj_BlockDecrypt::read_manifest_parts(dpp, manifest_bl,
+                                                       parts_len);
+    if (r < 0) {
+      ldpp_dout(dpp, 4) << "failed to read part lengths from the manifest" << dendl;
+      return r;
+    }
+    // store the encoded part lenghts in RGW_ATTR_CRYPT_PARTS
+    bufferlist parts_bl;
+    encode(parts_len, parts_bl);
+    src_attrs[RGW_ATTR_CRYPT_PARTS] = std::move(parts_bl);
+  }
+  return 0;
+}
+
 int RGWRados::transition_obj(RGWObjectCtx& obj_ctx,
                              RGWBucketInfo& bucket_info,
                              rgw_obj obj,
   if (ret < 0) {
     return ret;
   }
+  ret = fixup_manifest_to_parts_len(dpp, attrs);
+  if (ret < 0) {
+    return ret;
+  }
 
   if (read_mtime != mtime) {
     /* raced */